library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(ggplot2)
library(forcats)
library(here)
here() starts at /Users/avrilwang/Desktop/Project-Plasmodium
library(deSolve)
library(crone)
library(optimParallel)
Loading required package: parallel
library(doParallel)
Loading required package: foreach
Loading required package: iterators
library(doRNG)
Loading required package: rngtools
library(arrow)
Attaching package: ‘arrow’
The following object is masked from ‘package:utils’:
timestamp
library(stringr)
library(parallel)
library(ggpubr)
Notebook for plotting all of the figures for PloS Biology manuscript submission
Guidelines: taken from https://journals.plos.org/plosbiology/s/figures#loc-figure-file-requirements 1. format: eps 2. max file size: 10 MB 3. text size: Arial, Times, or Symbol font only in 8-12 point 2. figure size: Width: 789 – 2250 pixels (at 300 dpi). Height maximum: 2625 pixels (at 300 dpi).
#=========================================# figure 1: best single and co-infection cue #=========================================# Figure displaying the reaction norms of best single and co-infection.
#——- optimal cue reaction norm ———–# # read data
# single infection dynamics, reaction norms, and rugs
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
si_rn.df <- read_parquet(here("data/si_dyn/si_rn.parquet"))
si_rug.df <- read_parquet(here("data/si_dyn/si_rug.parquet"))
# co-infection dynamics, reaction norms, and rugs
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
ci_rn.df <- read_parquet(here("data/ci_dyn/ci_rn.parquet"))
ci_rug.df <- read_parquet(here("data/ci_dyn/ci_rug.parquet"))
process data for reaction norm
# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))
# get si_label with ci cue range
si_ci_rug.df <- ci_rug.df %>%
mutate(label_si = case_when(
label %in% c("I", "I1+I2") ~ "I",
label %in% c("I log","I1+I2 log") ~ "I log",
label %in% c("Ig", "Ig1+Ig2") ~ "Ig",
label %in% c("Ig log") ~ "Ig log",
label %in% c("sum", "I+Ig") ~ "I+Ig",
label %in% c("sum log", "I+Ig log") ~ "I+Ig log",
label == "R" ~ "R",
label == "R log" ~ "R log",
label %in% c("G", "G1+G2") ~ "G",
label == "G log" ~ "G log"
))
# get limit for si_rug
si_rug_lim.df <- si_rug.df %>%
filter(time <= 20) %>%
group_by(label)%>%
summarise(min = min(value, na.rm = T)*0.9,
max = max(value, na.rm = T)*1.1) %>%
select(label_si = label, min_si = min, max_si = max)
# filter to restriction conversion rate reaction norm range to cue ranges that appear in rug
## change to Inf/-inf to NA. Note that I am first joining with si rug lim to check which limit is larger, We will go with the cue range that has the largest span
ci_rug_lim.df <- si_ci_rug.df %>%
group_by(label) %>%
mutate(min = min(value, na.rm = T)*0.9,
max = max(value, na.rm = T)*1.1) %>%
distinct(label, .keep_all = T) %>%
select(label, label_si, min, max)
rug_lim.final <- ci_rug_lim.df %>% left_join(si_rug_lim.df, by = "label_si") %>%
mutate(final_min = min(min, min_si),
final_max = max(max, max_si))
# get second rug_lim.final for single infection
rug_lim.final2 <- rug_lim.final %>%
group_by(label_si) %>%
mutate(final_min = min(final_min, na.rm = T),
final_max = max(final_max, na.rm = T))
# filter ci_rn by limit
ci_rn.df2 <- ci_rn.df %>%
left_join(rug_lim.final, by = "label") %>%
group_by(label) %>%
filter(cue_range <= final_max & cue_range >= final_min)
match single infection rn with coinfection
# get ci label to si rug and filter by limit
si_rn.df2 <- left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c("label" = "label_si")) %>%
left_join(rug_lim.final, by = c("label_ci" = "label")) %>%
group_by(label_ci) %>%
filter(cue_range <= final_max & cue_range >= final_min) %>%
select(cue_range, cr, label_ci, label_si)
# get ci label to si rug
si_rug.df2 <- select(si_rug.df, value, label_si = label)
plot reaction norm
# join with ezlabel
ci_rn.df3 <- ci_rn.df2 %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rn.df3 <- si_rn.df2 %>% left_join(ez_label, by = "label_ci")
ci_rug.df3 <- ci_rug.df %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rug.df3 <- si_rug.df2 %>% left_join(ez_label, by = "label_si")
# redo order of cues
ci_rn.df3$ez_label <- factor(ci_rn.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
si_rn.df3$ez_label <- factor(si_rn.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
ci_rug.df3$ez_label <- factor(ci_rug.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
si_rug.df3$ez_label <- factor(si_rug.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
# plot
opt_cue_pl.B <- ggplot() +
geom_line(data = ci_rn.df3, aes(x = cue_range, y = cr, color = "Co-infection")) +
geom_point(data = ci_rn.df3 %>%
group_by(label) %>%
mutate(ten_th = round(n()/10)) %>%
filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Co-infection", shape = "Co-infection"), size = 2) +
geom_line(data = si_rn.df3, aes(x = cue_range, y = cr, color = "Single infection")) +
geom_point(data = si_rn.df3 %>%
group_by(label_ci) %>%
mutate(ten_th = round(n()/10)) %>%
filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Single infection", shape = "Single infection"), size = 2) +
geom_rug(data = ci_rug.df3, aes(x = value), color = "#4575b4", sides = "t", length = unit(0.1, "npc")) +
geom_rug(data = si_rug.df3, aes(x = value), color = "#fc8d59", sides = "b", length = unit(0.1, "npc")) +
facet_wrap(~ez_label, scales = "free_x", ncol = 2) +
ylim(-0.3, 1.3) +
theme_bw() +
labs(y = "Conversion rate", x = "Cue range", color = "Model", shape = "Model") +
scale_x_continuous(labels = function(x) format(x, scientific = T),
guide = guide_axis(check.overlap = TRUE)) +
theme(axis.text.x = element_text(size = 7),
legend.position = "bottom") +
scale_color_manual(values=c( "#4575b4", "#fc8d59")) +
theme(strip.text.x = element_text(margin = margin(b = 0.5, t = 0.5)))
#———- plot best fitness x vs y plot ————–# # import in data
# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
# co-infection dynamics
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
ez_label <- read.csv(here("data/ez_label.csv"))
process for final 20 days fitness
# get single infection maximum tau_cum for 20 days
si_fitness.df <- si_dyn.df %>%
filter(variable == "tau_cum" & time == 20)
# get co-infection maximum tau_cum for 20 days
ci_fitness.df <- ci_dyn.df %>%
filter(variable == "tau_cum1" & time == 20)
plot
si_opt.df
Error: object 'si_opt.df' not found
plot reaction norm and fitness value together
ggarrange(opt_cue_pl.A, opt_cue_pl.B, widths = c(0.6, 0.4), align = "h", labels = c("A", "B"))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(units = "px", dpi = 300, width = 2000, height = 1300, filename = here("figures/plos-bio/rn_fitness.tiff"), bg = "white", scale = 2.1)

#===========================================================# # Demographic stochasticity #===========================================================# #———- plot heat map—————# # import in all fitness files
file_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv", full.names = T)
name_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv")
name_ls <- gsub("*.csv", "", name_ls)
# 60, which is about right
length(file_ls)
# read in files
fitness.ls <- lapply(file_ls, read.csv)
# assign unique ID
fitness.ls <- mapply(cbind, fitness.ls, "ID" = name_ls, SIMPLIFY = F)
process data
# get metainfo from ID
fitness.ls2 <- mclapply(fitness.ls, function(x){
id_col <- x$ID
# string split to extract all info
cue <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
log <- unlist(str_split(unique(id_col), pattern = "_"))[[4]]
rand_var <- unlist(str_split(unique(id_col), pattern = "_"))[[5]]
# get mean
mean_fitness <- mean(x$max_fitness)
# get sd
sd_fitness <- sd(x$max_fitness)
# bind results
res <- cbind(x, cue= cue, log = log, rand_var = rand_var, mean_fitness = mean_fitness, sd_fitness = sd_fitness)
return(res)
})
Get reference data
reference_ls <- list.files(path = here("data/MC2"), pattern = "*.csv", full.names = T)
reference_name.ls <- gsub("*.csv", "", list.files(path = here("data/MC2/"), pattern = "*.csv"))
# read in the files
reference.ls <- lapply(reference_ls, read.csv)
# assign unique ID
reference.ls <- mapply(cbind, reference.ls, "ID" = reference_name.ls, SIMPLIFY = F)
# get meta data
reference.ls2 <- mclapply(reference.ls, function(x){
id_col <- x$ID
# string split to extract all info
cue <- unlist(str_split(unique(id_col), pattern = "_"))[[2]]
# get log
third_col <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
log <- ifelse(third_col == "log", "log10", "none")
# get mean
mean_fitness <- mean(x$max_fitness)
# get sd
sd_fitness <- sd(x$max_fitness)
# bind results
res <- cbind(x, cue= cue, log = log, rand_var = "all", ref_mean_fitness = mean_fitness, ref_sd_fitness = sd_fitness)
return(res)
})
combine MC partitioned and reference df
# get unique column values for each cue, log, and rand_var combo
fitness.ls3 <- do.call(rbind, fitness.ls2)
fitness.ls3 <- fitness.ls3 %>% dplyr::distinct(ID, .keep_all = T)
# repeat with reference
reference.ls3 <- do.call(rbind, reference.ls2)
reference.ls3 <- reference.ls3 %>% dplyr::distinct(ID, .keep_all = T)
# combine!
ref_fit.df <- left_join(fitness.ls3, reference.ls3, by = c("cue" = "cue", "log"= "log"))
compute proportion fitness and variation
ref_fit.df2 <- ref_fit.df %>%
mutate(p_sd = sd_fitness/ref_sd_fitness,
p_mean = ref_mean_fitness/mean_fitness,
cue_log = paste0(cue, "_", log),
label = case_when(
cue == "G" ~ "Gametocyte",
cue == "I" ~ "Asexual iRBC",
cue == "I+Ig" ~ "Asexual&sexual\niRBC",
cue == "Ig" ~ "Sexual iRBC",
cue == "R" ~ "RBC"
),
parameter = case_when(
rand_var.x == "rho" ~ "ρ",
rand_var.x == "phin" ~ "ϕn",
rand_var.x == "phiw"~ "ϕw",
rand_var.x == "psin" ~ "ψn",
rand_var.x == "psiw" ~ "ψw",
rand_var.x == "beta" ~ "β"
))
plot!
# variation
mc_b <- ggplot() +
geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_sd)) +
facet_wrap(~log) +
theme_bw() +
viridis::scale_fill_viridis() +
labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(sd("1 parameter randomized"), sd("all parameters randomized")))) +
theme(legend.position="top",
axis.text.x = element_text(angle = 45, hjust=1))
# mean fitness
mc_c <- ggplot() +
geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_mean)) +
facet_wrap(~log) +
theme_bw() +
viridis::scale_fill_viridis() +
labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(Mean("all parameters randomized"), Mean("1 parameter randomized")))) +
theme(legend.position="top",
axis.text.x = element_text(angle = 45, hjust=1))
mc_partition <- ggarrange(mc_b, mc_c, ncol = 1)
#————– get violine plot of variation in fitness ——————–# # read MC data
# read in dymamics
mc_G_log.dyn <- read_parquet(here("data/MC2/mc_G_log_dyn.parquet"))
mc_G.dyn <- read_parquet(here("data/MC2/mc_G_dyn.parquet"))
mc_R_log.dyn <- read_parquet(here("data/MC2/mc_R_log_dyn.parquet"))
mc_R.dyn <- read_parquet(here("data/MC2/mc_R_dyn.parquet"))
mc_I_log.dyn <- read_parquet(here("data/MC2/mc_I_log_dyn.parquet"))
mc_I.dyn <- read_parquet(here("data/MC2/mc_I_dyn.parquet"))
mc_Ig_log.dyn <- read_parquet(here("data/MC2/mc_Ig_log_dyn.parquet"))
mc_Ig.dyn <- read_parquet(here("data/MC2/mc_Ig_dyn.parquet"))
mc_I_Ig_log.dyn <- read_parquet(here("data/MC2/mc_I+Ig_log_dyn.parquet"))
mc_I_Ig.dyn <- read_parquet(here("data/MC2/mc_I+Ig_dyn.parquet"))
# read in fitness
mc_G_log.fitness <- read.csv(here("data/MC2/mc_G_log_fitness.csv"))
mc_G.fitness <- read.csv(here("data/MC2/mc_G_fitness.csv"))
mc_R_log.fitness <- read.csv(here("data/MC2/mc_R_log_fitness.csv"))
mc_R.fitness <- read.csv(here("data/MC2/mc_R_fitness.csv"))
mc_I_log.fitness <- read.csv(here("data/MC2/mc_I_log_fitness.csv"))
mc_I.fitness <- read.csv(here("data/MC2/mc_I_fitness.csv"))
mc_Ig_log.fitness <- read.csv(here("data/MC2/mc_Ig_log_fitness.csv"))
mc_Ig.fitness <- read.csv(here("data/MC2/mc_Ig_fitness.csv"))
mc_I_Ig_log.fitness <- read.csv(here("data/MC2/mc_I+Ig_log_fitness.csv"))
mc_I_Ig.fitness <- read.csv(here("data/MC2/mc_I+Ig_fitness.csv"))
examine variation
# quantify variance and mean
fitness_var.df <- fitness.df %>%
dplyr::group_by(id) %>%
dplyr::summarise(median = median(max_fitness)) %>%
dplyr::mutate(id = forcats::fct_reorder(id, mean))
Error in `mutate_cols()`:
! Problem with `mutate()` column `id`.
ℹ `id = forcats::fct_reorder(id, mean)`.
✖ length(f) == length(.x) is not TRUE
Caused by error in `forcats::fct_reorder()`:
! length(f) == length(.x) is not TRUE
Backtrace:
1. ... %>% dplyr::mutate(id = forcats::fct_reorder(id, mean))
7. forcats::fct_reorder(id, mean)
8. base::stopifnot(length(f) == length(.x))
9. base::stop(simpleError(msg, call = if (p <- sys.parent(1L)) sys.call(p)))
plot violin with difference in deterministic model fitness and mean model fitness

#————– plot together———————–#

#=========================================================# # time series conversion rate for single and co-infection #=========================================================# #——— single infection conversion rate heat map————–# # process info for single infection
# get fintess
si_cr.df <- si_dyn.df %>%
filter(time <= 20 & variable == "cr")
# good cue bad cue
si_cue.dv <- si_fitness.df %>%
mutate(classification = case_when(
value > 9.2 ~ "Good performing",
value <= 9.2 ~ "Poor performing"
))
# join with classificaiton
si_cr.df2 <- si_cr.df %>%
left_join(select(si_cue.dv, id, classification, fitness_si = value), by = "id") %>%
left_join(ez_label, by = c("id" = "id_si"))
# split into top erforming and poor-performing cues
si_cr.high <- si_cr.df2 %>% filter(classification == "Good performing")
si_cr.poor <- si_cr.df2 %>% filter(classification == "Poor performing")
si_cue.dv
plot single infection conversion rate heatmap
# plot poor performing
si_cr.pl1 <- ggplot() +
geom_tile(data = si_cr.poor, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_si), fill = value)) +
labs(x = "Time (days)", y = "Low performing\nsingle infection cues", fill = "Conversion rate") +
scale_fill_viridis_c(limits = c(0, 1)) +
xlim(1, 20) +
theme_bw()
# plot high perfomring
si_cr.pl2 <- ggplot() +
geom_tile(data = si_cr.high, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_si), fill = value)) +
labs(x = "", y = "High performing\nsingle infection cues", fill = "Conversion rate") +
scale_fill_viridis_c(limits = c(0, 1)) +
xlim(1, 20) +
theme_bw()
—————–co-infection conversion rate heatmap———–
plot co-infeciton convesion rate heatmap
plot
i
Error: object 'i' not found
#——— assemble final figure ————–#
si_cr.pl <- ggarrange(si_cr.pl2, si_cr.pl1, common.legend = T, ncol = 1, nrow = 2)
ci_cr.pl <- ggarrange(ci_cr.pl2, ci_cr.pl1, common.legend = T, ncol = 1, nrow = 2)
ggarrange(si_cr.pl, ci_cr.pl, labels = c("A", "B"), ncol = 2, common.legend = T)
ggsave(units = "px", dpi = 300, width = 2000, height = 1000, filename = here("figures/plos-bio/time_cr.tiff"), bg = "white", scale = 1.7)
#——————————————–# # dual cue optimization figure #——————————————–#
source(here("functions/chabaudi_si_clean_high.R"))
source(here("functions/chabaudi_si_clean.R"))
source(here("functions/par_to_hm_te.R"))
#———- plotting fitness of dual vs single cue opt ———# # import in previous data
# dual cue fitness
dual_fitness.df <- read.csv(here("data/dual_cue_opt4/dual_cue_fitness_20.csv"))
## make label and filter out very low fitness
dual_fitness.df <- dual_fitness.df %>%
mutate(temp_label = gsub("log", "log10", label),
temp_label_b = gsub("log", "log10", label_b),
label_final = paste0(temp_label, "+", temp_label_b)) %>%
filter(value > 2)
# get single cue fitness
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
si_fitness.df <- si_dyn.df %>%
filter(variable == "tau_cum" & time == 20)
# join si and dual cue
dual_si_fitness.df <- dual_fitness.df %>%
left_join(select(si_fitness.df, id, si_fitness = value), by = "id") %>%
left_join(select(si_fitness.df, id_b = id, si_fitness_b = value), by = "id_b") %>%
mutate(si_fitness_max = ifelse(si_fitness > si_fitness_b, si_fitness, si_fitness_b),
dual_label = gsub("log", "log10", paste(label, "+", label_b)))
plot

#———– time series conversion rate ————-# # dynamics simulation of high parameter cues (these serve as reference points)
# best dual cue combo
dual.cr <- chabaudi_si_clean(
parameters_cr = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(6, 7, by = 1/500),
cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
cue = "R",
cue_b = "I",
log_cue = "log10",
log_cue_b = "log10",
solver = "vode",
dyn = T
)
Error in force(parameters) : object 'parameters_tsukushi' not found
plot
ggplot() +
geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 3) +
labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
xlim(0, 20) +
scale_color_manual(values = c("#fc8d59","#fdcb44","black", "#4575b4")) +
theme_bw() +
theme(legend.position="bottom") +
guides(color = guide_legend(nrow = 2, byrow = TRUE))
Warning: Removed 3 rows containing missing values (`geom_line()`).
Warning: Removed 3 rows containing missing values (`geom_point()`).

#———— reaction norm heatmap of R log10 + I log10 ————# # process data
max(R_Ig.dyn$Ig)
[1] 175754.2
plot
# just testing for sexual iRBC vs RBC
ggplot() +
geom_path(data = R_Ig.dyn, aes(x = Ig, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
geom_point(data = R_Ig.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = Ig, y = log_R), color = "white") +
scale_x_continuous(trans = "log10") +
xlim(0, 200000) +
labs(y = "RBC log10", x = "Sexual iRBC log10", fill = "Conversion rate") +
theme_dark()
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

save figure for poster
dual_rn.pl2 <- ggplot() +
geom_raster(data = R_I.hm, aes(x = cue_range_b, y = cue_range, fill = cr)) +
scale_fill_viridis_c() +
geom_path(data = R_I.dyn, aes(x = log_I, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
geom_point(data = R_I.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = log_I, y = log_R), color = "white") +
xlim(0.99*min(hablar::s(R_I.dyn$log_I), na.rm = T), 1.01* max(hablar::s(R_I.dyn$log_I), na.rm = T)) +
ylim(0.99*min(hablar::s(R_I.dyn$log_R), na.rm = T),1.01* max(hablar::s(R_I.dyn$log_R), na.rm = T)) +
labs(y = "RBC log10", x = "Asexual iRBC log10", fill = "Conversion rate") +
theme_dark() + theme(legend.position="top")
dual_cr.pl2 <- ggplot() +
geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 2) +
labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
xlim(0, 20) +
scale_color_manual(values = c("#4575b4", "#91bfdb","#fc8d59","#fdcb44")) +
theme_bw() +
theme(legend.position="top") +
guides(color = guide_legend(nrow = 2, byrow = TRUE))
ggarrange(dual_cr.pl2, dual_rn.pl2, align = "h", widths = c(1.25, 1))
ggsave(here("poster/dual_cue.png"), width = 7, height = 4)
#——– assemble final figure ————-#

#============================================# # real life disease curve #============================================# # execute code from report 10 to get final dataset The following graphs will be made: - R vs iRBC - R log10 vs iRBC - R vs iRBC log10 - R log10 vs iRBC log10
G vs iRBC
G log10 vs iRBC
G vs iRBC log10
G log10 vs iRBC log10
R vs G
R log10 vs G
R vs G log10
R log10 vs G log10
R on y-axis
r_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = asex)) +
geom_path(aes(y = RBC, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = asex)) +
geom_path(aes(y = log10(RBC), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
r_ilog.dc <-ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = log10(asex))) +
geom_path(aes(y = RBC, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_ilog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = log10(asex))) +
geom_path(aes(y = log10(RBC), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
G on y-axis
g_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = gam, x = asex)) +
geom_path(aes(y = gam, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
glog_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(gam), x = asex)) +
geom_path(aes(y = log10(gam), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
g_ilog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = gam, x = log10(asex))) +
geom_path(aes(y = gam, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
glog_ilog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(gam), x = log10(asex))) +
geom_path(aes(y = log10(gam), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
R vs G
r_g.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = gam)) +
geom_path(aes(y = RBC, x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "Gametocyte per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_g.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = gam)) +
geom_path(aes(y = log10(RBC), x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "Gametocyte per µL", y = "log10(RBC per µL)", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
r_glog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = log10(gam))) +
geom_path(aes(y = RBC, x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(Gametocyte) per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_glog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = log10(gam))) +
geom_path(aes(y = log10(RBC), x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(Gametocyte) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
plot together


#===========================================# # static competition #===========================================# #——- heat map —————# # calculate fitness difference for 20 days
static.ls <- lapply(static.ls, read_parquet)
Error: file must be a "InputStream"
plot
ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.

ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(here("figures/plos-bio/static_competition_a.tiff"), units = "px", width = 2250, height = 1500, scale = 1.2, dpi=300, bg = "white")

#—— effect cue perception ——-# ## logging
# get non-logged pairings
static_nolog <- static.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "none")
static_log <- static.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "log")
static_log.df <- left_join(
select(static_nolog, cue_1, label_ci_2, log_1, None = fitness_difference),
select(static_log, cue_1, label_ci_2, log_1, Log = fitness_difference),
by = c("cue_1", "label_ci_2")) %>%
filter(!is.na(None) & !is.na(Log)) %>%
mutate(classification = ifelse(Log > None, "Logged better", "Not logged better"))
combined
static_nocomb <- static.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "none")
static_comb <- static.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "comb")
static_comb.df <- left_join(
select(static_nocomb, cue_1, label_ci_2, log_1, Self = fitness_difference),
select(static_comb, cue_1, label_ci_2, log_1, Total = fitness_difference),
by = c("cue_1", "log_1", "label_ci_2")) %>%
filter(!is.na(Total) & !is.na(Self)) %>%
mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
plot

ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")
ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")
ggsave(here("figures/plos-bio/static_competition_b.tiff"), units = "px", width = 1000, height = 2000, scale = 1.2, dpi=300, bg = "white")

#===========================================# # invasion analysis #===========================================# # import in data (already 20 days )
invade.df <- read.csv(here("data/ci_invasion.csv"))
process data for invasion matrix
invade.mat <- invade.df %>%
group_by(V1 = pmin(mut_id, res_id), V2 = pmax(mut_id, res_id)) %>% # group by cue competition, irregardless of order
mutate(id_alt = paste0(V1, V2),
invade = case_when(
fitness > 0 ~ "invade",
fitness < 0 ~ "not invade"
)) %>%
group_by(id_alt) %>%
mutate(
mut_is_V1 = case_when(
mut_id == V1 ~ "V1_invade",
mut_id != V1 ~ "V1_invaded")) %>%
arrange(id_alt) %>%
select(fitness, V1, V2, id_alt, invade, mut_is_V1) %>%
tidyr::pivot_wider(names_from = mut_is_V1, values_from = fitness) %>%
group_by(id_alt) %>%
mutate(V1_invade2 = gsub("NA", "", paste0(V1_invade, collapse = "")),
V1_invaded2 = gsub("NA", "", paste0(V1_invaded, collapse = ""))) %>%
distinct(id_alt, .keep_all = T) %>%
mutate(
category = case_when(
V1_invade2 > 0 & V1_invaded2 > 0 ~ "Mutual invasion",
V1_invade2 > 0 & V1_invaded2 < 0 ~ "Only strain 1 invasion",
V1_invade2 < 0 & V1_invaded2 > 0 ~ "Only strain 2 invasion",
V1_invade2 < 0 & V1_invaded2 < 0 ~ "Mutual non-invasion"
)) %>%
select(V1, V2, invasion = category)
invade.df %>% filter(mut_id == "G-i_none")
invade.df %>% filter(res_id == "G-i_none")
invade.mat4 <- rbind(
select(invade.mat3, V1_label, V2_label, invasion),
select(invade.mat3, V2_label = V1_label, V1_label = V2_label) %>% mutate(invasion = NA)) %>%
mutate(
invasion_2 = case_when(
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
)) %>%
filter(!is.na(V1_label))
Adding missing grouping variables: `id_alt`
Adding missing grouping variables: `id_alt`
plot invasion matrix

create summary bar chart
# create a stacked barchart for summary
## filter out na
invade.matalt <- invade.mat3 %>% na.exclude()
# get frquency from both sides. Note when grouping for V2, from the perspective of cue 2, scenarrio when strain 2 invade = strain 1 invade
invade.matalt1 <- invade.matalt %>% group_by(V1_label, invasion) %>%
summarize(frequency_1 = n())
invade.matalt2 <- invade.matalt %>%
mutate(invasion_alt = case_when(
invasion == "Only strain 1 invasion" ~ "Only strain 2 invasion",
invasion == "Only strain 2 invasion" ~ "Only strain 1 invasion",
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Mutual non-invasion" ~ "Mutual non-invasion"
)) %>%
group_by(V2_label, invasion_alt) %>%
summarize(frequency_2 = n())
# full join and sum. has confirmed all of them add up to 14
invade.matalt3 <- full_join(invade.matalt1, invade.matalt2, by = c("V1_label" = "V2_label", "invasion" = "invasion_alt"))
invade.matalt3[is.na(invade.matalt3)] <- 0
invade.matalt4 <- invade.matalt3 %>%
mutate(freq = frequency_1 + frequency_2) %>%
mutate(temp = case_when(
invasion == "Only strain 1 invasion" ~ freq
)) %>%
group_by(V1_label) %>%
mutate(invade_1_freq = max(temp, na.rm = T)) %>%
mutate(invasion_2 = case_when(
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
))

plot together


ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))
ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))
ggsave(here("figures/plos-bio/invasion_a.tiff"), units = "px", width = 2250, height = 1100, scale = 1.4, dpi=300, bg = "white")

#—————- invasion pairwise comparison—————–# ## proces data
combined
invade_nocomb <- invade.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "none")
invade_comb <- invade.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "comb")
invade_comb.df <- left_join(
select(invade_nocomb, cue_1, res_id, log_1, Self = fitness),
select(invade_comb, cue_1, res_id, log_1, Total = fitness),
by = c("cue_1", "log_1", "res_id")) %>%
filter(!is.na(Total) & !is.na(Self)) %>%
mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
invade_comb.df
plot

ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggsave(here("figures/plos-bio/invasion_b.tiff"), units = "px", width = 2250, height = 850, scale = 1.2, dpi=300, bg = "white")

#===========================================# # Cue performance across single, co-infection, static, and invasion #===========================================#
plot

#-=====================# # Partitioning best cue #=====================-# #——- single infection ———–# # redo some optimization (lower fitness in no R than default)
source(here("functions/chabaudi_si_clean_R.R"))
source(here("functions/chabaudi_si_clean_N.R"))
# I none
cl <- makeCluster(detectCores()); setDefaultCluster(cl = cl)
I_no_R <- optimParallel(
par = rep(0.5,4), # start at 0.5x4
fn = chabaudi_si_clean_R,
control = list(trace = 6, fnscale = -1),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000),
cue = "I",
log_cue = "none",
solver = "vode")
stopCluster(cl)
# 0.144021 -43.1046 2030.27 -524.686
# 8.69589
import and process data
# import in data
si_partition.ls <- list.files(path = here("data/partition/si/"), pattern = "*.csv", full.names = T)
si_partition.ls <- lapply(si_partition.ls, read.csv)
si_partition.df <- do.call(rbind, si_partition.ls)
# combine with si fitness (default)
si_partition.df <- si_partition.df %>% left_join(select(si_fitness.df, id, fitness = value), by = "id")
# make longer
si_partition.df2 <- tidyr::pivot_longer(si_partition.df, c(fitness_R, fitness_N, fitness_W, fitness))
# calculate coefficient of variation. Also rename
si_partition.df2 <- si_partition.df2 %>%
group_by(name) %>%
mutate(cv = sd(value)/mean(value)*100,
mean = mean(value),
category = case_when(
name == "fitness_R" ~ "No RBC limitation",
name == "fitness_W" ~ "No targeted immunity",
name == "fitness_N" ~ "No indiscriminate\nimmunity",
name == "fitness" ~ "Default"
))
plot
library(ungeviz)
# raw fitness
si_partition.pl1 <- ggplot() +
geom_vpline(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = mean, group = category, color = category), show.legend = F, size = 1) +
geom_point(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value), size = 2, alpha = 0.7) +
geom_line(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value, group = id), alpha = 0.2) +
labs(x = "Fitness", y = "Conditions") +
theme_bw()
# coefficient of variation
si_partition.pl2 <- ggplot() +
geom_bar(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = cv), stat = "identity") +
labs(x = "Coefficient of\nvariation (%)", y = "") +
theme_bw() +
theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
si_partition.pl <- ggarrange(si_partition.pl1, si_partition.pl2, widths = c(1, 0.3), align = "h")
si_partition.pl
ggsave(here("figures/plos-bio/partition_fitness.tiff"), width = 7, height = 4)
#——- consequences of no targeted immunity ————# # get dynamics of no targeted immunity
get_dyn <- function(df){
source(here("functions/chabaudi_si_clean_W.R"))
id <- df$id
cue <- df$cue
log <- df$log
par <- c(df$var_W1, df$var_W2, df$var_W3, df$var_W4)
cue_range <- seq(df$low, df$high, by = df$by)
# get dynamics
dyn <- chabaudi_si_clean_W(
parameters_cr = par,
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = cue_range,
cue = cue,
log_cue = log,
solver = "vode",
dyn = T
)
# combine
dyn2 <- cbind(dyn, id = id, cue = cue, log = log)
write_parquet(dyn2, paste0(here("data/partition/si_dyn/"), id, "_noW_dyn.parquet"))
}
get df to run
# join with cue_range
cue_range_si.df <- read.csv(here("data/cue_range_si.csv"))
si_partition.df3 <- si_partition.df %>% left_join(select(cue_range_si.df, low, high, by, id), "id")
# lapply loop
si_partition.ls <- split(si_partition.df3, seq(nrow(si_partition.df3)))
mclapply(si_partition.ls, get_dyn)
process dataframe
# import in dataframe
no_W.ls <- list.files(here("data/partition/si_dyn/"), pattern = "*noW_dyn.parquet", full.names = T)
no_W.df <- lapply(no_W.ls, read_parquet)
no_W.df <- do.call(rbind, no_W.df)
# combine with ez label
ez_label <- read.csv(here("data/ez_label.csv"))
no_W.df <- left_join(no_W.df, ez_label, by = c("id" = "id_si"))
# get conversion rate
no_W.cr <- no_W.df %>% filter(variable == "cr")
no_W.I <- no_W.df %>% filter(variable == "I")
# get default conversion rate dynamics
si_dyn.df <- left_join(si_dyn.df, ez_label, by = c("id" = "id_si"))
si_dyn.cr <- si_dyn.df %>% filter(variable == "cr")
si_dyn.I <- si_dyn.df %>% filter(variable == "I")
plot conversion rate
mechanism: targeted immunity led to lower parasite density in the initial stages, which prevents parasites from making the switch from no conversion rate to high conversion rate. When parsite density undergoes drastic increase at the beginning due to lower immunity, this presents a higher degree of signal that allows parasite to make the switch appropriately
partition_cr.pl <- ggplot() +
geom_line(data = no_W.cr, aes(x = time, y= value, color = "No targeted immunity")) +
geom_line(data = si_dyn.cr, aes(x = time, y= value, color = "Default")) +
facet_wrap(~ez_label_si, ncol = 5) +
xlim(0, 20) +
geom_vline(xintercept = 7) +
labs(x = "Time (days)", y = "Conversion rate", color = "Condition") +
theme_bw()
no_W.cr
#—– cue state ————–#
function to get cue states
# function to get cue states
get_cue_state <- function(df){
cue <- trimws(gsub("_log|_none", "", unique(df$id)))
if(cue != "I+Ig"){
df2 <- df %>% filter(variable == cue)
if(str_detect(unique(df$id), "log")){
df2 <- df2 %>%
mutate(value = log10(value))
}
}
if(cue == "I+Ig"){
df2 <- df %>% filter(variable %in% c("I", "Ig")) %>%
group_by(time) %>%
mutate(value = sum(value))
if(str_detect(unique(df$id), "log")){
df2 <- df2 %>%
mutate(value = log10(value))
}
}
df2$value[df2$value == -Inf] <- 0
write_parquet(df2, paste0(here("data/partition/si_default_state/"), unique(df$id), "_noW_state.parquet"))
}
run function
# split dynamics based on id
no_W.split <- split(no_W.df, no_W.df$id)
# run function
mclapply(no_W.split, get_cue_state)
# get dataframe
no_W.state <- list.files(here("data/partition/si_state/"), pattern = "*.parquet", full.names = T)
no_W.state <- lapply(no_W.state, read_parquet)
no_W.state <- do.call(rbind, no_W.state)
no_W.state$value[no_W.state$value < 0] <- 0
# get same for si infection
default.split <- split(si_dyn.df, si_dyn.df$id)
mclapply(default.split, get_cue_state)
default.state <- list.files(here("data/partition/si_default_state/"), pattern = "*.parquet", full.names = T)
default.state <- lapply(default.state, read_parquet)
default.state <- do.call(rbind, default.state)
default.state$value[default.state$value < 0] <- 0
# manually correct non-logging
I_Ig.corr <- no_W.state %>% filter(id == "I+Ig_log") %>%
mutate(value = log10(value))
I_Ig.corr$value[I_Ig.corr$value < 0] <- 0
no_W.state2 <- no_W.state %>% filter(id != "I+Ig_log")
no_W.state2 <- no_W.state2 %>% rbind(no_W.state2, I_Ig.corr)
plot
absence of targeted immunity led to drastic increase in parasite density in early phases of infection. This produces high signal intensity for parasite and host-based cues, especially non-logged ones, which allows for state differentation. While this can be viewed as a modelling artifiact, it should be noted that the logged cues seldom changed as these changes in early infection did little to alter the actual early signal intensity sensed by the parasite. In an environment where there is heterogeneity in host response, and thus, signal, logging allows for parasites to adapt optimal strategy whereas non-logged cues must contend with sensitivity to immunity.
# function to individually plot stuff
plot_state <- function(df1, df2){
# plot state dynamics
state_pl <- ggplot() +
geom_line(data = df1, aes(x = time, y = value, color = name, group = name)) +
facet_wrap(~ez_label_si, scales = "free") +
xlim(1,20) +
theme_bw() +
theme(legend.position="none") +
labs(x = "", y = "Cue") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE)) +
scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59"))
# plot conversion rate dynamics
cr_pl <- ggplot() +
geom_raster(data = df2, aes(x = time, y = name, fill = value)) +
xlim(1,20) +
theme_bw() +
labs(x = "Time (days)") +
theme(axis.title.y=element_blank(),
axis.ticks.y=element_blank(),
legend.position = "none") +
scale_fill_viridis_c(lim = c(0, 1))
# arrange
ggarrange(state_pl, cr_pl, ncol = 1, nrow = 2, align = "v", heights = c(1, 0.4))
ggsave(paste0(here("figures/plos-bio/partition/"), unique(df1$id), ".tiff"), width = 4.5, height = 3.5)
}
split
# combine state
noW_default.state <- left_join(
select(no_W.state2, time, `No targeted\nimmunity` = value, id, ez_label_si),
select(default.state %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.state2 <- tidyr::pivot_longer(noW_default.state, c(`No targeted\nimmunity`, `Default`))
# combine conversion raster
noW_default.cr <- left_join(
select(no_W.cr, time, `No targeted\nimmunity` = value, id, ez_label_si),
select(si_dyn.cr %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.cr2 <- tidyr::pivot_longer(noW_default.cr, c(`No targeted\nimmunity`, `Default`))
# split
noW_default_state.ls <- split(noW_default.state2, noW_default.state2$id)
noW_default_cr.ls <- split(noW_default.cr2, noW_default.cr2$id)
# run function
mapply(plot_state, noW_default_state.ls, noW_default_cr.ls)
#——– reaction norms of default vs optimized ————# # get reaction norm and rug data
source(here("functions/par_to_df.R"))
# Gametocyte
g_log.rn <- par_to_df(par = c(1.211521, -3.936778, -1.312944, -1.285713), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g_log.rn2 <- par_to_df(par = c(1.393860539, -4.253007616, -0.313947029, -2.000857344), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g.rn <- par_to_df(par = c(0.04061288, -9.31445958, 74.13015506, -431.5984364), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
g.rn2 <- par_to_df(par = c(0.541729073, -3.904616443, 0.87487412, -0.694177021), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
# I+Ig
I_Ig_log.rn <- par_to_df(par = c(3.594042, 4.157744, -13.530672, 2.599905), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig_log.rn2 <- par_to_df(par = c(63.71893822, -87.77671601, -56.55475514, -66.02209549), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig.rn <- par_to_df(par = c(0.3159297, -46.1104558, 1250.752908, -6.1982093), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
I_Ig.rn2 <- par_to_df(par = c(0.731982784, -21.69799449, 149.7841876, 17.02551769), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
# convert log to non-logged scale
g_log.rn$cue_range <- 10^(g_log.rn$cue_range)
g_log.rn2$cue_range <- 10^(g_log.rn2$cue_range)
I_Ig_log.rn$cue_range <- 10^(I_Ig_log.rn$cue_range)
I_Ig_log.rn2$cue_range <- 10^(I_Ig_log.rn2$cue_range)
# get rug
g_log.rug <- default.state %>%
filter(label_si == "G log") %>%
mutate(value = 10^value) %>%
select(label_si, value)
g_log.rug2 <- no_W.state %>%
filter(label_si == "G log") %>%
mutate(value = 10^value) %>%
filter(value <= 6*(10^4)) %>%
select(label_si, value)
I_Ig_log.rug <- default.state %>%
filter(label_si == "I+Ig log") %>%
select(label_si, value)
I_Ig_log.rug2 <- no_W.state %>%
filter(label_si == "I+Ig log") %>%
select(label_si, value)
g.rug <- default.state %>%
filter(label_si == "G") %>%
select(label_si, value)
g.rug2 <- no_W.state %>%
filter(label_si == "G" & value <= 6*(10^4)) %>%
select(label_si, value)
I_Ig.rug <- default.state %>%
filter(label_si == "I+Ig") %>%
select(label_si, value)
I_Ig.rug2 <- no_W.state %>%
filter(label_si == "I+Ig") %>%
select(label_si, value)
# get rug limits
rug_lim <- rbind(g_log.rug,
g_log.rug2,
I_Ig_log.rug,
I_Ig_log.rug2,
g.rug,
g.rug2,
I_Ig.rug,
I_Ig.rug2) %>%
group_by(label_si) %>%
summarize(max = max(hablar::s(value), na.rm = T),
min = min(hablar::s(value), na.rm = T))
# combine and filter
rn <- rbind(
cbind(g_log.rn, label_si = "G log", condition = "Default"),
cbind(g_log.rn2, label_si = "G log", condition = "No targeted\nimmunity"),
cbind(g.rn, label_si = "G", condition = "Default"),
cbind(g.rn2, label_si = "G", condition = "No targeted\nimmunity"),
cbind(I_Ig_log.rn, label_si = "I+Ig log", condition = "Default"),
cbind(I_Ig_log.rn2, label_si = "I+Ig log", condition = "No targeted\nimmunity"),
cbind(I_Ig.rn, label_si = "I+Ig", condition = "Default"),
cbind(I_Ig.rn2, label_si = "I+Ig", condition = "No targeted\nimmunity")
) %>%
left_join(rug_lim, by = "label_si") %>%
group_by(label_si) %>%
filter(cue_range <= max & cue_range >= min)
# combine rug
rug <- rbind(cbind(g_log.rug, condition = "Default"),
cbind(g_log.rug2, condition = "No targeted\nimmunity"),
cbind(g.rug, condition = "Default"),
cbind(g.rug2, condition = "No targeted\nimmunity"),
cbind(I_Ig_log.rug, condition = "Default"),
cbind(I_Ig_log.rug2, condition = "No targeted\nimmunity"),
cbind(I_Ig.rug, condition = "Default"),
cbind(I_Ig.rug2, condition = "No targeted\nimmunity"))
# cobine with ezlabel
rn2 <- rn %>% left_join(ez_label, by = "label_si")
rug2 <- rug %>% left_join(ez_label, by = "label_si")
# filter rug
default.rug <- rug2 %>% filter(condition == "Default")
no.rug <- rug2 %>% filter(condition == "No targeted\nimmunity")
plot
ggplot() +
geom_line(data = rn2, aes(x = cue_range, y = cr, color = condition)) +
geom_rug(data = default.rug, aes(x = value, color = condition), sides = "b") +
geom_rug(data = no.rug, aes(x = value, color = condition), sides = "t") +
facet_wrap(~fct_relevel(ez_label_si, c("Gametocyte log10", "Gametocyte", "Asexual&sexual\niRBC log10", "Asexual&sexual iRBC")), scales = "free_x") +
scale_x_continuous(labels = function(x) format(x, scientific = TRUE)) +
theme_bw() +
scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59")) +
ylim(0, 1.1) +
labs(x = "Cue range", y = "Conversion rate", color = "Condition")
ggsave(here("figures/plos-bio/partition_rn.tiff"), width = 7.5, height = 6)
get conversion rate legend
noW_default.cr %>% filter(id == "G_log") %>%
ggplot() +
geom_raster(aes(x = time, y = id, fill = Default)) +
xlim(1,20) +
theme_bw() +
labs(x = "Time (days)",
fill = "Conversion rate") +
theme(axis.title.y=element_blank(),
axis.ticks.y=element_blank(),) +
scale_fill_viridis_c(lim = c(0, 1))
ggsave(here("figures/plos-bio/cr_legend.tiff"))
#================================# # Disease curves for single, co-infection, and invasion #===============================# # get data for disease curves
# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
# co-infection dynamics (mon-cue)
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
# dual cue dynamics
dual_dyn.df <- read_parquet(here("data/dual_cue_dyn/dual_cue_dyn.parquet"))
#——- single cue comparison —————# # process data
# process dynamics -> turn skinny
si_dc.df <- si_dyn.df %>%
filter(variable == "I" | variable == "Ig" | variable == "R") %>%
tidyr::pivot_wider(names_from = variable, values_from = value) %>%
mutate(total = I+Ig)
# process dynamics -> turn skinny
si_dc.df <- si_dyn.df %>%
filter(variable == "I" | variable == "Ig" | variable == "R") %>%
tidyr::pivot_wider(names_from = variable, values_from = value) %>%
mutate(total = I+Ig)
plot

#———- co-infection monocue ————-#
# get relevent variables
ci_dc.df <- ci_dyn.df %>%
filter(variable == "I1" | variable == "Ig1" | variable == "R")
# morph into skinny format
ci_dc.df <- tidyr::pivot_wider(ci_dc.df, names_from = variable, values_from = value, id_cols = c(time, label)) %>%
mutate(total = I1+Ig1)
# good cue bad cue
ci_cue.dv <- ci_fitness.df %>%
mutate(classification = case_when(
value > 2.25 ~ "High-performing",
value <= 2.25 ~ "Poor-performing"
))
# join with classificaiton
ci_dc.df2 <- ci_dc.df %>% left_join(ci_cue.dv, by = "label")
# split into top erforming and poor-performing cues
ci_dc.high <- ci_dc.df2 %>% filter(classification == "High-performing")
ci_dc.poor <- ci_dc.df2 %>% filter(classification == "Poor-performing")
# join high performing with label
ci_dc.high2 <- ci_dc.high %>% left_join(ez_label, by = c("label" = "label_ci"))
#write_parquet(ci_dc.high2, here("data/disease_curve/ci_dc_high.parquet"))
#write_parquet(ci_dc.poor, here("data/disease_curve/ci_dc_poor.parquet"))
plot
ci_dc.poor <- read_parquet(here("data/disease_curve/ci_dc_poor.parquet"))
ci_dc.high2 <- read_parquet(here("data/disease_curve/ci_dc_high.parquet"))
# plot
ci_dc.pre <- ggplot() +
geom_path(data = ci_dc.poor, aes(x= total, y = R, group = label), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Co-infection\ngood performing cues", x = "Asexual & sexual iRBC per µL", y = "RBC per µL") +
theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
guides(shape = FALSE)
ci_dc.pl <- ci_dc.pre +
geom_point(data = ci_dc.high2 %>% filter(row_number() %% 1000 ==0), aes(x = total, y = R, color = ez_label, shape = ez_label), size = 3) +
geom_path(data = ci_dc.high2, aes(x= total, y = R, group = ez_label, color = ez_label), size = 1, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
scale_color_manual(values=c( "#4575b4", "#fc8d59", "#fdcb44", "#91bfdb")) +
guides(color = guide_legend(override.aes = list(size = 0.1)))
#——— dual cue ————————–# # process data
plot
dual_dc.high <- read_parquet(here("data/disease_curve/dual_dc_high.parquet"))
dual_dc.poor <- read_parquet(here("data/disease_curve/dual_dc_poor.parquet"))
dual_dc.high2 <- dual_dc.high %>%
filter(label_alt == "R log10 + I log10")
# add
dual_dc.pre <- ggplot() +
geom_path(data = dual_dc.poor, aes(x= total, y = R, group = label_alt), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "High-performing\ndual cues per µL", x = "Asexual & sexual iRBC", y = "RBC per µL") +
theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
guides(shape = FALSE)
dual_dc.pl <- dual_dc.pre +
geom_point(data = dual_dc.high2 %>% filter(row_number() %% 1000 ==0), aes(x = total, y = R, shape = label_alt), color = "#4575b4", size = 3) +
geom_path(data = dual_dc.high2, aes(x= total, y = R, group = label_alt), color = "#4575b4", size = 1, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme(legend.position = "none") +
guides(color = guide_legend(override.aes = list(size = 0.1)))
#——— co-infection static —————-#
# import in dynamics data
static_dyn.ls <- list.files(path = here("data/ci_static/"), pattern = "*.parquet", full.names = T)
static_dyn.ls <- lapply(static_dyn.ls, read_parquet)
# filter variable and transform
static_dyn.ls2 <- mclapply(static_dyn.ls, function(x){
x %>%
filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>%
mutate(id_alt = paste(id_1, id_2)) %>%
tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
mutate(total1 = I1+Ig1, total2 = I2+Ig2)
})
static_dc.df <- do.call(rbind, static_dyn.ls2)
static_dc.df <- static_dc.df %>%
mutate(id_1 = gsub(" .*", "", id_alt),
id_2 = gsub(".* ", "", id_alt)) %>%
filter(id_1 != id_2)
#write_parquet(static_dc.df, here("data/disease_curve/static_dc.parquet"))
further processing
static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
# get winners and losers
## import in fitness
static_fitness.df <- read.csv(here("data/ci_static.csv"))
## get winner situation
static_fitness.df2 <- static_fitness.df %>%
filter(id_1 != id_2) %>%
mutate(winning_id = case_when(
fitness_difference > 0 ~ id_1,
fitness_difference< 0 ~ id_2
),
losing_id = case_when(
fitness_difference < 0 ~ id_1,
fitness_difference> 0 ~ id_2
))
# left join
static_dc.df2 <- static_dc.df %>%
left_join(select(static_fitness.df2, id_1, id_2, winning_id, losing_id, fitness_difference), by = c("id_1", "id_2"))
# get winner-loser difference in terms of I+Ig also filter out to onyl very strong fitness difference
static_dc.df3 <- static_dc.df2 %>%
mutate(total_diff = case_when(
fitness_difference > 0 ~ total1-total2,
fitness_difference< 0 ~ total2-total2
),
total_winner = case_when(
fitness_difference > 0 ~ total1,
fitness_difference< 0 ~ total2
),
total_loser = case_when(
fitness_difference > 0 ~ total2,
fitness_difference< 0 ~ total1
)) %>%
filter(abs(fitness_difference) > 0.5)
plot
static_dc.pl <- ggplot() +
geom_path(data = static_dc.df3, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
geom_path(data = static_dc.df3, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59")) +
theme_bw() +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1))
#———co-infection invasion —————# # get invasion dynamic
# get invasion df
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
# get cue range
ci_cue_range <- read.csv(here("data/cue_range_ci.csv"))
invasion_fitness.df2 <- invasion_fitness.df %>%
left_join(select(ci_cue_range, id, mut_cue = cue, mut_low = low, mut_high = high, mut_by = by), by = c("mut_id"= "id")) %>%
left_join(select(ci_cue_range, id, res_cue = cue, res_low = low, res_high = high, res_by = by), by = c("res_id"= "id"))
function to get dynamic
get_invasion_dyn <- function(df){
# get cues
mut_cue <- df$mut_cue
res_cue <- df$res_cue
# get info of cues (for co infection)
if(stringr::str_detect(mut_cue, "-i")){mut_cue = gsub("*-i", "1", mut_cue)}
if(stringr::str_detect(mut_cue, "-i", negate = T)){mut_cue = mut_cue}
if(stringr::str_detect(res_cue, "-i")){res_cue = gsub("*-i", "2", res_cue)}
if(stringr::str_detect(res_cue, "-i", negate = T)){res_cue = res_cue}
# get log
mut_log <- ifelse(stringr::str_detect(df$mut_id, "log"), "log10", "none")
res_log <- ifelse(stringr::str_detect(df$res_id, "log"), "log10", "none")
# get parameters
mut_par <- c(df$mut_var1_opt, df$mut_var2_opt, df$mut_var3_opt, df$mut_var4_opt)
res_par <- c(df$res_var1, df$res_var2, df$res_var3, df$res_var4)
# get cue range
mut_cue_range <- seq(df$mut_low, df$mut_high, by = df$mut_by)
res_cue_range <- seq(df$res_low, df$res_high, by = df$res_by)
# get dynamics of co infection
ci_dyn <- chabaudi_ci_clean(
parameters_cr_1 = mut_par,
parameters_cr_2 = res_par,
immunity = "tsukushi",
parameters = parameters_tsukushi,
cue_1 = mut_cue,
cue_2 = res_cue,
cue_range_1 = mut_cue_range,
cue_range_2 = res_cue_range,
log_cue_1 = mut_log,
log_cue_2 = res_log,
solver = "vode",
time_range = seq(0, 30, 0.001),
dyn = T)
# append label to all df
ci_dyn2 <- cbind(ci_dyn, mut_id = df$mut_id, res_id = df$res_id)
# write
write_parquet(ci_dyn2, paste0(here("data/ci_invasion_dyn/"), df$mut_id, "-", df$res_id, ".parquet"))
}
run dynamic funciton
# get function and parameters
source(here("functions/chabaudi_ci_clean.R"))
parameters_tsukushi <- c(R1 = 8.89*(10^6), # slightly higher
lambda = 3.7*(10^5),
mu = 0.025,
p = 8*(10^-6), # doubled form original
alpha = 1,
alphag = 2,
beta = 5.721,
mum = 48,
mug = 4,
I0 = 43.85965,
Ig0 = 0,
a = 150,
b = 100,
sp = 1,
psin = 16.69234,
psiw = 0.8431785,
phin = 0.03520591,
phiw = 550.842,
iota = 2.18*(10^6),
rho = 0.2627156)
# split
invasion.ls <- split(invasion_fitness.df2, seq(nrow(invasion_fitness.df2)))
# run function
mclapply(invasion.ls, get_invasion_dyn, mc.cores = 4)
process data
# import in invasion dynamics
invasion_dyn.ls <- list.files(path = here("data/ci_invasion_dyn"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls <- lapply(invasion_dyn.ls, read_parquet)
# filter and so on
invasion_dyn.ls2 <- mclapply(invasion_dyn.ls[167:177], mc.cores = 4, function(x){
x2 <- x %>%
filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>%
mutate(id_alt = paste(mut_id, res_id)) %>%
select(id_alt, time, variable, value) %>%
tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
mutate(total1 = I1+Ig1, total2 = I2+Ig2)
write_parquet(x2, paste0(here("data/disease_curve/ci_invasion/"), unique(x2$id_alt), "_dc.parquet"))
})
# fetch data
invasion_dyn.ls2 <- list.files(path = here("data/disease_curve/ci_invasion"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls2 <- lapply(invasion_dyn.ls2, read_parquet)
invasion_dc.df <- do.call(rbind, invasion_dyn.ls2)
invasion_dc.df <- invasion_dc.df %>%
mutate(mut_id = gsub(" .*", "", id_alt),
res_id = gsub(".* ", "", id_alt)) %>%
filter(mut_id != res_id)
#write_parquet(invasion_dc.df, here("data/disease_curve/invasion_dc.parquet"))
further processing
invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
# get winners and losers
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
invasion_dc.df2 <- invasion_dc.df %>%
left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>%
mutate(
total_winner = case_when(
fitness> 0 ~ total1,
fitness< 0 ~ total2
),
total_loser = case_when(
fitness > 0 ~ total2,
fitness < 0 ~ total1
)) %>%
filter(abs(fitness) > 0.5)
plot
invasion_dc.pl <- ggplot() +
geom_path(data = invasion_dc.df2, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
geom_path(data = invasion_dc.df2, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59")) +
theme_bw() +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) %>%
theme(legend.position = "none")
#——— quantifying disease curve area ————# # function to calculate area between sets of points -> from https://stackoverflow.com/questions/3672260/area-covered-by-a-point-cloud-with-r
library(splancs)
Loading required package: sp
Spatial Point Pattern Analysis Code in S-Plus
Version 2 - Spatial and Space-Time analysis
Attaching package: ‘splancs’
The following object is masked from ‘package:dplyr’:
tribble
cha<-function(df){
x <- df$total
y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}
library(splancs)
cha<-function(df){
x <- df$total
y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}
loop to get area: single infection
# join with fitness
si_fitness.df <- si_fitness.df %>% left_join(ez_label, by = c("id" = "id_si"))
Error in is.data.frame(y) : object 'ez_label' not found
coinfection
# split
ci_dc_high.ls <- split(ci_dc.high2, ci_dc.high2$ez_label)
ci_dc_poor.ls <- split(ci_dc.poor, ci_dc.poor$label)
# run function to find area
ci_dc_high.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc_high.ls, cha)), id_alt = names(lapply(ci_dc_high.ls, cha)), value = unique(ci_dc.high2$value))
ci_dc_poor.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc_poor.ls, cha)), id_alt = names(lapply(ci_dc_poor.ls, cha)), value = unique(ci_dc.poor$value))
# edit and join
ci_dc_high.area2 <- ci_dc_high.area %>%
select(area, value) %>%
mutate(condition = "Co-infection")
ci_dc_poor.area2 <- ci_dc_poor.area %>%
select(area, value) %>%
mutate(condition = "Co-infection")
dual cue
# split
dual.dc <- read_parquet(here("data/disease_curve/dual_dc.parquet"))
dual_dc.ls <- split(dual.dc, dual.dc$label_alt)
# get area
dual_dc.area <- cbind.data.frame(area = as.numeric(lapply(dual_dc.ls, cha)), id_alt = names(lapply(dual_dc.ls, cha)))
# bind with fitness
dual_fitness.df <- dual_fitness.df %>% mutate(id_alt = paste(label, "+", label_b))
dual_dc.area2 <- dual_dc.area %>%
left_join(dual_fitness.df, by = "id_alt") %>%
select(area, value) %>%
mutate(condition = "Dual-cue") %>%
filter(value > 2)
dual_dc.area2
#—— get fitted scatter plot for all single infection, co infection, and dual cue ——–#
# plot
library("ggpmisc")
Loading required package: ggpp
Attaching package: ‘ggpp’
The following object is masked from ‘package:ggplot2’:
annotate
#——- plot together with disease curve ——–#
# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
# co-infection
ci_vir.pl <- ggarrange(ci_dc.pl, ci_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
#——— static area comparison ————-# # compute area
# import in dc dynamic and fitness
static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
static_fitness.df <- read.csv(here("data/ci_static.csv"))
# get winner and loser
static_dc.df4 <- static_dc.df %>%
left_join(select(static_fitness.df, id_1, id_2, fitness_difference), by = c("id_1", "id_2")) %>%
filter(id_1 != id_2) %>%
mutate(
total_winner = case_when(
fitness_difference > 0 ~ total1,
fitness_difference< 0 ~ total2
),
total_loser = case_when(
fitness_difference > 0 ~ total2,
fitness_difference< 0 ~ total1
))%>%
filter(abs(fitness_difference) > 0.5)
# split by winner and loser
static_dc.ls1 <- split(select(static_dc.df4, R, total = total_winner), static_dc.df4$id_alt)
static_dc.ls2 <- split(select(static_dc.df4, R, total = total_loser), static_dc.df4$id_alt)
# get area
static_win.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls1, cha)), status = "Winner")
static_loser.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls2, cha)), status = "Loser")
# pair
static.area <- cbind(select(static_win.area, Winner = area),
select(static_loser.area, Loser = area)) %>%
mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))
plot static

#——— invasion area comparison —————–# # get area
# import in dc dynamic and fitness
invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
invasion_dc.df4 <- invasion_dc.df %>%
left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>%
mutate(
total_winner = case_when(
fitness> 0 ~ total1,
fitness< 0 ~ total2
),
total_loser = case_when(
fitness > 0 ~ total2,
fitness < 0 ~ total1
)) %>%
filter(abs(fitness) > 0.5)
# split by winner and loser
invasion_dc.ls1 <- split(select(invasion_dc.df4, R, total = total_winner), invasion_dc.df4$id_alt)
invasion_dc.ls2 <- split(select(invasion_dc.df4, R, total = total_loser), invasion_dc.df4$id_alt)
# get area
invasion_win.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls1, cha)), status = "Winner")
invasion_loser.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls2, cha)), status = "Loser")
# pair
invasion.area <- cbind(select(invasion_win.area, Winner = area),
select(invasion_loser.area, Loser = area)) %>%
mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))
plot

#—— plot together ————-#
# pairwise comparison for static and invasive comeptition
heterocue_comp.pl <- ggarrange(static_area.pl, invasion_area.pl, ncol = 2, nrow = 1, align = "v")
# join inthe other disease curves
ggarrange(si_vir.pl, ci_vir.pl, dual_vir.pl, heterocue_comp.pl, ncol = 2, nrow = 2, labels = c("A", "B", "C", "D"), heights = c(1, 0.8))
ggsave(here("figures/plos-bio/virulence.tiff"), units = "px", width = 2250, height = 1600, scale = 1.9, dpi=300, bg = "white")

#====================================# # dual cue dynamics figure #===================================#
get dual dynamics
dual.dyn <- chabaudi_si_clean(
parameters_cr = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 30, by = 1e-3),
cue_range = seq(6, 7, by = 1/500),
cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
cue = "R",
cue_b = "I",
log_cue = "log10",
log_cue_b = "log10",
solver = "vode",
dyn = T
)
# filter out relevent dataframes
dual.dyn_f <- dual.dyn %>%
filter(variable %in% c("I", "Ig", "G", "R", "N", "W"))
# cr only
dual.dyn_cr <- dual.dyn %>% filter(variable == "cr")
plot
dual_I.plt <- ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "I"), aes(x = time, y = value/(10^5)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "I" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^5, name="Asexual iRBC per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_Ig.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "Ig"), aes(x = time, y = value/(10^5)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "Ig" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^5, name="Sexual iRBC per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_G.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "G"), aes(x = time, y = value/(10^4)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "G" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^4)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^4, name="Gametocyte per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_R.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "R"), aes(x = time, y = value/(10^7)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "R" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^7)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^7, name="RBC per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_N.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "N"), aes(x = time, y = value*10),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "N" & row_number() %% 1000 == 0),
aes(x = time, y = value*10), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*0.1, name="Indiscriminate immunity")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_W.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "W"), aes(x = time, y = value*2),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "W" & row_number() %% 1000 == 0),
aes(x = time, y = value*2), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*0.5, name="Targeted immunity")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
plot together
ggarrange(dual_I.plt, dual_Ig.plt, dual_G.plt, dual_R.plt, dual_N.plt, dual_W.plt, nrow = 3, ncol = 2, align = "hv", labels = c("A", "B", "C", "D", "E", "F"))
ggsave(here("figures/plos-bio/dual_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1, dpi=300, bg = "white")
#======================================# # Single and co-infection verification #======================================# # single infection
# import in all single infection data
si_val.ls <- list.files(path = here("data/si_validation"), pattern = "*.csv", full.names = T)
si_val.df <- lapply(si_val.ls, read.csv)
si_val.df <- do.call(rbind, si_val.df)
# get max fitness from simulation. left join with si_opt
si_opt.df <- read.csv(here("data/si_opt.csv"))
# we can see that all of the randomly simulated models have a fitness value that is less than the optimized model
si_val.df2 <- select(si_val.df, V1, id) %>%
left_join(si_opt.df, by =c("id" = "id")) %>%
mutate(fitness_difference = fitness_20 - V1) %>%
left_join(select(ez_label, id_si, ez_label_si), by = c("id" = "id_si"))
plot
si_val.plt <- ggplot(data = si_val.df2, aes(x = fitness_difference)) +
geom_histogram(bins = 50) +
geom_vline(xintercept = 0, color = "#fc8d59") +
facet_wrap(~ez_label_si, scales = "free", ncol = 3) +
labs(x = "Optimized fitness - random fitness", y = "Frequency") +
theme_bw()
ci_val.plt <- ggplot(data = ci_val.df2, aes(x = V1)) +
geom_histogram(bins = 50) +
geom_vline(xintercept = 0, color = "#fc8d59") +
facet_wrap(~ez_label, scales = "free", ncol = 4) +
labs(x = "Fitness difference between\noptimized and random strain", y = "Frequency") +
theme_bw()
ggarrange(si_val.plt, ci_val.plt, align = "hv", labels = c("A", "B"), widths = c(3,4))
ggsave(here("figures/plos-bio/validation.tiff"), units = "px", width = 2250, height = 1300, scale = 1.6, dpi=300, bg = "white")
#=========================# # Monte carlo dynamics supplementary #=========================# # run code in report 16
mc_dyn_a <- ggplot() +
geom_line(data = reference.df, aes(x = time, y = cr)) +
geom_ribbon(data = diff.df, aes(x = time, ymin = cr_bot, ymax = cr_top), alpha = 0.5, fill = "#fc8d59") +
facet_wrap(~cue, ncol = 2) +
labs(x = "Time (days)", y = "Conversion rate") +
theme_bw()
# plot fitness timeseries. When if tiness lost? At the latter part
mc_dyn_b <- ggplot() +
geom_line(data = reference.df, aes(x = time, y = tau)) +
geom_ribbon(data = diff.df, aes(x = time, ymin = tau_bot, ymax = tau_top), alpha = 0.5, fill = "#fc8d59") +
facet_wrap(~cue, ncol = 2) +
labs(x = "Time (days)", y = "Transmission potential") +
theme_bw()
ggarrange(mc_dyn_a, mc_dyn_b, ncol = 1, align = "v", labels = c("A", "B"))
Warning: Removed 1 row containing missing values (`geom_line()`).
ggsave(here("figures/plos-bio/MC_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1.3, dpi=300, bg = "white")

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkZVNvbHZlKQpsaWJyYXJ5KGNyb25lKQpsaWJyYXJ5KG9wdGltUGFyYWxsZWwpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShkb1JORykKbGlicmFyeShhcnJvdykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGdncHVicikKYGBgCgpOb3RlYm9vayBmb3IgcGxvdHRpbmcgYWxsIG9mIHRoZSBmaWd1cmVzIGZvciBQbG9TIEJpb2xvZ3kgbWFudXNjcmlwdCBzdWJtaXNzaW9uCgpHdWlkZWxpbmVzOiB0YWtlbiBmcm9tIGh0dHBzOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc2Jpb2xvZ3kvcy9maWd1cmVzI2xvYy1maWd1cmUtZmlsZS1yZXF1aXJlbWVudHMKMS4gZm9ybWF0OiBlcHMKMi4gbWF4IGZpbGUgc2l6ZTogMTAgTUIKMy4gdGV4dCBzaXplOiBBcmlhbCwgVGltZXMsIG9yIFN5bWJvbCBmb250IG9ubHkgaW4gOC0xMiBwb2ludAoyLiBmaWd1cmUgc2l6ZTogV2lkdGg6IDc4OSDigJMgMjI1MCBwaXhlbHMgKGF0IDMwMCBkcGkpLiBIZWlnaHQgbWF4aW11bTogMjYyNSBwaXhlbHMgKGF0IDMwMCBkcGkpLgoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKZmlndXJlIDE6IGJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gY3VlCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKRmlndXJlIGRpc3BsYXlpbmcgdGhlIHJlYWN0aW9uIG5vcm1zIG9mIGJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24uCgojLS0tLS0tLSBvcHRpbWFsIGN1ZSByZWFjdGlvbiBub3JtIC0tLS0tLS0tLS0tIwojIHJlYWQgZGF0YQpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uIGR5bmFtaWNzLCByZWFjdGlvbiBub3JtcywgYW5kIHJ1Z3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKc2lfcm4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvc2lfZHluL3NpX3JuLnBhcnF1ZXQiKSkKc2lfcnVnLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9ydWcucGFycXVldCIpKQoKIyBjby1pbmZlY3Rpb24gZHluYW1pY3MsIHJlYWN0aW9uIG5vcm1zLCBhbmQgcnVncwpjaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX2R5bi5wYXJxdWV0IikpCmNpX3JuLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9ybi5wYXJxdWV0IikpCmNpX3J1Zy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfcnVnLnBhcnF1ZXQiKSkKYGBgCgojIHByb2Nlc3MgZGF0YSBmb3IgcmVhY3Rpb24gbm9ybQpgYGB7cn0KIyBpbXBvcnQgbGFiZWxsaW5nIHNjaGVtZQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBnZXQgc2lfbGFiZWwgd2l0aCBjaSBjdWUgcmFuZ2UKc2lfY2lfcnVnLmRmIDwtIGNpX3J1Zy5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX3NpID0gY2FzZV93aGVuKAogICAgbGFiZWwgJWluJSBjKCJJIiwgIkkxK0kyIikgfiAiSSIsCiAgICBsYWJlbCAlaW4lIGMoIkkgbG9nIiwiSTErSTIgbG9nIikgfiAiSSBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJJZyIsICJJZzErSWcyIikgfiAiSWciLAogICAgbGFiZWwgJWluJSBjKCJJZyBsb2ciKSB+ICJJZyBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJzdW0iLCAiSStJZyIpIH4gIkkrSWciLAogICAgbGFiZWwgJWluJSBjKCJzdW0gbG9nIiwgIkkrSWcgbG9nIikgfiAiSStJZyBsb2ciLAogICAgbGFiZWwgPT0gIlIiIH4gIlIiLAogICAgbGFiZWwgPT0gIlIgbG9nIiB+ICJSIGxvZyIsCiAgICBsYWJlbCAlaW4lIGMoIkciLCAiRzErRzIiKSB+ICJHIiwKICAgIGxhYmVsID09ICJHIGxvZyIgfiAiRyBsb2ciCiAgKSkgCgojIGdldCBsaW1pdCBmb3Igc2lfcnVnCnNpX3J1Z19saW0uZGYgPC0gc2lfcnVnLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCkgJT4lCiAgZ3JvdXBfYnkobGFiZWwpJT4lIAogIHN1bW1hcmlzZShtaW4gPSBtaW4odmFsdWUsIG5hLnJtID0gVCkqMC45LAogICAgICAgICBtYXggPSBtYXgodmFsdWUsIG5hLnJtID0gVCkqMS4xKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpID0gbGFiZWwsIG1pbl9zaSA9IG1pbiwgbWF4X3NpID0gbWF4KQoKIyBmaWx0ZXIgdG8gcmVzdHJpY3Rpb24gY29udmVyc2lvbiByYXRlIHJlYWN0aW9uIG5vcm0gcmFuZ2UgdG8gY3VlIHJhbmdlcyB0aGF0IGFwcGVhciBpbiBydWcKIyMgY2hhbmdlIHRvIEluZi8taW5mIHRvIE5BLiBOb3RlIHRoYXQgSSBhbSBmaXJzdCBqb2luaW5nIHdpdGggc2kgcnVnIGxpbSB0byBjaGVjayB3aGljaCBsaW1pdCBpcyBsYXJnZXIsIFdlIHdpbGwgZ28gd2l0aCB0aGUgY3VlIHJhbmdlIHRoYXQgaGFzIHRoZSBsYXJnZXN0IHNwYW4KY2lfcnVnX2xpbS5kZiA8LSBzaV9jaV9ydWcuZGYgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgbXV0YXRlKG1pbiA9IG1pbih2YWx1ZSwgbmEucm0gPSBUKSowLjksCiAgICAgICAgIG1heCA9IG1heCh2YWx1ZSwgbmEucm0gPSBUKSoxLjEpICU+JSAKICBkaXN0aW5jdChsYWJlbCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIHNlbGVjdChsYWJlbCwgbGFiZWxfc2ksIG1pbiwgbWF4KQoKcnVnX2xpbS5maW5hbCA8LSBjaV9ydWdfbGltLmRmICU+JSBsZWZ0X2pvaW4oc2lfcnVnX2xpbS5kZiwgYnkgPSAibGFiZWxfc2kiKSAlPiUgCiAgbXV0YXRlKGZpbmFsX21pbiA9IG1pbihtaW4sIG1pbl9zaSksCiAgICAgICAgIGZpbmFsX21heCA9IG1heChtYXgsIG1heF9zaSkpCgojIGdldCBzZWNvbmQgcnVnX2xpbS5maW5hbCBmb3Igc2luZ2xlIGluZmVjdGlvbgpydWdfbGltLmZpbmFsMiA8LSBydWdfbGltLmZpbmFsICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIG11dGF0ZShmaW5hbF9taW4gPSBtaW4oZmluYWxfbWluLCBuYS5ybSA9IFQpLAogICAgICAgICBmaW5hbF9tYXggPSBtYXgoZmluYWxfbWF4LCBuYS5ybSA9IFQpKQoKIyBmaWx0ZXIgY2lfcm4gYnkgbGltaXQKY2lfcm4uZGYyIDwtIGNpX3JuLmRmICU+JSAKICBsZWZ0X2pvaW4ocnVnX2xpbS5maW5hbCwgYnkgID0gImxhYmVsIikgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgZmlsdGVyKGN1ZV9yYW5nZSA8PSBmaW5hbF9tYXggJiBjdWVfcmFuZ2UgPj0gZmluYWxfbWluKQpgYGAKCiMgbWF0Y2ggc2luZ2xlIGluZmVjdGlvbiBybiB3aXRoIGNvaW5mZWN0aW9uIApgYGB7cn0KIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnIGFuZCBmaWx0ZXIgYnkgbGltaXQKc2lfcm4uZGYyIDwtIGxlZnRfam9pbihzaV9ybi5kZiwgc2VsZWN0KGV6X2xhYmVsLCBsYWJlbF9zaSwgbGFiZWxfY2kpLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9zaSIpKSAlPiUgCiAgbGVmdF9qb2luKHJ1Z19saW0uZmluYWwsIGJ5ICA9IGMoImxhYmVsX2NpIiA9ICJsYWJlbCIpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2kpICU+JSAKICBmaWx0ZXIoY3VlX3JhbmdlIDw9IGZpbmFsX21heCAmIGN1ZV9yYW5nZSA+PSBmaW5hbF9taW4pICU+JSAKICBzZWxlY3QoY3VlX3JhbmdlLCBjciwgbGFiZWxfY2ksIGxhYmVsX3NpKQoKIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnCnNpX3J1Zy5kZjIgPC0gc2VsZWN0KHNpX3J1Zy5kZiwgdmFsdWUsIGxhYmVsX3NpID0gbGFiZWwpIApgYGAKCiMgcGxvdCByZWFjdGlvbiBub3JtCmBgYHtyfQojIGpvaW4gd2l0aCBlemxhYmVsCmNpX3JuLmRmMyA8LSBjaV9ybi5kZjIgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKc2lfcm4uZGYzIDwtIHNpX3JuLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9jaSIpCmNpX3J1Zy5kZjMgPC0gY2lfcnVnLmRmICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCnNpX3J1Zy5kZjMgPC0gc2lfcnVnLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCmBgYAoKCmBgYHtyfQojIHJlZG8gb3JkZXIgb2YgY3VlcwpjaV9ybi5kZjMkZXpfbGFiZWwgPC0gZmFjdG9yKGNpX3JuLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpIAoKc2lfcm4uZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ybi5kZjMkZXpfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJBc2V4dWFsIGlSQkMiLCAiQXNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgYXNleHVhbCBpUkJDIiwgIlRvdGFsIGFzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZXh1YWwgaVJCQyIsICJTZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzZXh1YWwmc2V4dWFsIGlSQkMiLCAiQXNleHVhbCZzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBpUkJDIiwgIlRvdGFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYW1ldG9jeXRlIiwgIkdhbWV0b2N5dGUgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBnYW1ldG9jeXRlIiwgIlRvdGFsIHNleHVhbCBpUkJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUkJDIiwgIlJCQyBsb2cxMCIpKQoKY2lfcnVnLmRmMyRlel9sYWJlbCA8LSBmYWN0b3IoY2lfcnVnLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpCgpzaV9ydWcuZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ydWcuZGYzJGV6X2xhYmVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQXNleHVhbCBpUkJDIiwgIkFzZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGFzZXh1YWwgaVJCQyIsICJUb3RhbCBhc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2V4dWFsIGlSQkMiLCAiU2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2V4dWFsJnNleHVhbCBpUkJDIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgaVJCQyIsICJUb3RhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2FtZXRvY3l0ZSIsICJHYW1ldG9jeXRlIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgZ2FtZXRvY3l0ZSIsICJUb3RhbCBzZXh1YWwgaVJCQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJCQyIsICJSQkMgbG9nMTAiKSkKIyBwbG90Cm9wdF9jdWVfcGwuQiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBjaV9ybi5kZjMsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gIkNvLWluZmVjdGlvbiIpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gY2lfcm4uZGYzICU+JSAKICAgIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgICBtdXRhdGUodGVuX3RoID0gcm91bmQobigpLzEwKSkgJT4lIAogICAgZmlsdGVyKHJvd19udW1iZXIoKSAlJSB0ZW5fdGggPT0gMCksIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gIkNvLWluZmVjdGlvbiIsIHNoYXBlID0gIkNvLWluZmVjdGlvbiIpLCBzaXplID0gMikgKwogIGdlb21fbGluZShkYXRhID0gc2lfcm4uZGYzLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uIikpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9ybi5kZjMgJT4lIAogICAgZ3JvdXBfYnkobGFiZWxfY2kpICU+JSAKICAgIG11dGF0ZSh0ZW5fdGggPSByb3VuZChuKCkvMTApKSAlPiUgCiAgICBmaWx0ZXIocm93X251bWJlcigpICUlIHRlbl90aCA9PSAwKSwgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiU2luZ2xlIGluZmVjdGlvbiIsIHNoYXBlID0gIlNpbmdsZSBpbmZlY3Rpb24iKSwgc2l6ZSA9IDIpICsKICBnZW9tX3J1ZyhkYXRhID0gY2lfcnVnLmRmMywgYWVzKHggPSB2YWx1ZSksIGNvbG9yID0gIiM0NTc1YjQiLCBzaWRlcyA9ICJ0IiwgbGVuZ3RoID0gdW5pdCgwLjEsICJucGMiKSkgKwogIGdlb21fcnVnKGRhdGEgPSBzaV9ydWcuZGYzLCBhZXMoeCA9IHZhbHVlKSwgY29sb3IgPSAiI2ZjOGQ1OSIsIHNpZGVzID0gImIiLCBsZW5ndGggPSB1bml0KDAuMSwgIm5wYyIpKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWwsIHNjYWxlcyA9ICJmcmVlX3giLCBuY29sID0gMikgKwogIHlsaW0oLTAuMywgMS4zKSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh5ID0gIkNvbnZlcnNpb24gcmF0ZSIsIHggPSAiQ3VlIHJhbmdlIiwgY29sb3IgPSAiTW9kZWwiLCBzaGFwZSA9ICJNb2RlbCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUKSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGNoZWNrLm92ZXJsYXAgPSBUUlVFKSkgKyAKICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzQ1NzViNCIsICIjZmM4ZDU5IikpICsKICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKGIgPSAwLjUsIHQgPSAwLjUpKSkKYGBgCgojLS0tLS0tLS0tLSBwbG90IGJlc3QgZml0bmVzcyB4IHZzIHkgcGxvdCAtLS0tLS0tLS0tLS0tLSMKIyBpbXBvcnQgaW4gZGF0YQpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uIGR5bmFtaWNzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCgojIGNvLWluZmVjdGlvbiBkeW5hbWljcwpjaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX2R5bi5wYXJxdWV0IikpCgplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQpgYGAKCiMgcHJvY2VzcyBmb3IgZmluYWwgMjAgZGF5cyBmaXRuZXNzCmBgYHtyfQojIGdldCBzaW5nbGUgaW5mZWN0aW9uIG1heGltdW0gdGF1X2N1bSBmb3IgMjAgZGF5cwpzaV9maXRuZXNzLmRmIDwtIHNpX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXVfY3VtIiAmIHRpbWUgPT0gMjApCgojIGdldCBjby1pbmZlY3Rpb24gbWF4aW11bSB0YXVfY3VtIGZvciAyMCBkYXlzCmNpX2ZpdG5lc3MuZGYgPC0gY2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0xIiAmIHRpbWUgPT0gMjApCgojIGpvaW4gdG9nZXRoZXIgdHdvIGRhdGFmcmFtZXMgYW5kIGFkZCBsYWJlbHMKc2lfY2lfZml0bmVzcy5kZiA8LSBzZWxlY3QoY2lfZml0bmVzcy5kZiwgZml0bmVzc19jaSA9IHZhbHVlLCBsYWJlbF9jaSA9IGxhYmVsKSAlPiUgCiAgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9jaSIpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHNpX2ZpdG5lc3MuZGYsIGZpdG5lc3Nfc2kgPSB2YWx1ZSwgaWRfc2kgPSBpZCksIGJ5ID0gImlkX3NpIikKYGBgCgojIHBsb3QKYGBge3J9Cm9wdF9jdWVfcGwuQSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gc2lfY2lfZml0bmVzcy5kZiwgYWVzKHggPSBmaXRuZXNzX3NpLCB5ID0gZml0bmVzc19jaSwgY29sb3IgPSBlel9sYWJlbF9zaSwgc2hhcGUgPSBlel9sYWJlbF9zaSksIHNpemUgPSAzLjUpICsKICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPSBzaV9jaV9maXRuZXNzLmRmLCBhZXMobGFiZWwgPSBlel9sYWJlbCwgeCA9IGZpdG5lc3Nfc2ksIHkgPSBmaXRuZXNzX2NpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAid2hpdGUiLHhsaW0gPSBjKC1JbmYsIEluZiksIHlsaW0gPSBjKE5BLCBOQSkpICsKICBsYWJzKHggPSAiTWF4aW11bSBzaW5nbGUgaW5mZWN0aW9uIGZpdG5lc3MiLCB5ID0gIk1heGltdW0gQ28taW5mZWN0aW9uIGZpdG5lc3MgKHBlciBzdHJhaW4pIiwKICAgICAgIGNvbG9yID0gIlNpbmdsZSBpbmZlY3Rpb24gY3VlIiwgc2hhcGUgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWUiKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDE1OjI0KSArCiAgbGltcyh4ID0gYyg4LCAxMC41KSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkuMiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgYWxwaGEgPSAwLjUpICsgIyBzaSBnb29kIGN1ZSBjdXRvZmYKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAyLjI1LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDAuNSkgKyAjIGNpIGdvb2QgY3VlIGN1dG9mZgogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpCmBgYAoKIyBwbG90IHJlYWN0aW9uIG5vcm0gYW5kIGZpdG5lc3MgdmFsdWUgdG9nZXRoZXIKYGBge3J9CmdnYXJyYW5nZShvcHRfY3VlX3BsLkEsIG9wdF9jdWVfcGwuQiwgd2lkdGhzID0gYygwLjYsIDAuNCksIGFsaWduID0gImgiLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkKZ2dzYXZlKHVuaXRzID0gInB4IiwgZHBpID0gMzAwLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDEzMDAsIGZpbGVuYW1lID0gaGVyZSgiZmlndXJlcy9wbG9zLWJpby9ybl9maXRuZXNzLnRpZmYiKSwgYmcgPSAid2hpdGUiLCBzY2FsZSA9IDIuMSkKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgRGVtb2dyYXBoaWMgc3RvY2hhc3RpY2l0eQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tLS0tIHBsb3QgaGVhdCBtYXAtLS0tLS0tLS0tLS0tLS0jCiMgaW1wb3J0IGluIGFsbCBmaXRuZXNzIGZpbGVzCmBgYHtyfQpmaWxlX2xzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUNfcGFydGl0aW9uZWQvIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKbmFtZV9scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL01DX3BhcnRpdGlvbmVkLyIpLCBwYXR0ZXJuID0gIiouY3N2IikKbmFtZV9scyA8LSBnc3ViKCIqLmNzdiIsICIiLCBuYW1lX2xzKQoKIyA2MCwgd2hpY2ggaXMgYWJvdXQgcmlnaHQKbGVuZ3RoKGZpbGVfbHMpCgojIHJlYWQgaW4gZmlsZXMKZml0bmVzcy5scyA8LSBsYXBwbHkoZmlsZV9scywgcmVhZC5jc3YpCgojIGFzc2lnbiB1bmlxdWUgSUQKZml0bmVzcy5scyA8LSBtYXBwbHkoY2JpbmQsIGZpdG5lc3MubHMsICJJRCIgPSBuYW1lX2xzLCBTSU1QTElGWSA9IEYpCmBgYAoKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgZ2V0IG1ldGFpbmZvIGZyb20gSUQKZml0bmVzcy5sczIgPC0gbWNsYXBwbHkoZml0bmVzcy5scywgZnVuY3Rpb24oeCl7CiAgaWRfY29sIDwtIHgkSUQKICAjIHN0cmluZyBzcGxpdCB0byBleHRyYWN0IGFsbCBpbmZvCiAgY3VlIDwtIHVubGlzdChzdHJfc3BsaXQodW5pcXVlKGlkX2NvbCksIHBhdHRlcm4gPSAiXyIpKVtbM11dCiAgbG9nIDwtIHVubGlzdChzdHJfc3BsaXQodW5pcXVlKGlkX2NvbCksIHBhdHRlcm4gPSAiXyIpKVtbNF1dCiAgcmFuZF92YXIgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1s1XV0KICAKICAjIGdldCBtZWFuCiAgbWVhbl9maXRuZXNzIDwtIG1lYW4oeCRtYXhfZml0bmVzcykKICAjIGdldCBzZAogIHNkX2ZpdG5lc3MgPC0gc2QoeCRtYXhfZml0bmVzcykKICAKICAjIGJpbmQgcmVzdWx0cwogIHJlcyA8LSBjYmluZCh4LCBjdWU9IGN1ZSwgbG9nID0gbG9nLCByYW5kX3ZhciA9IHJhbmRfdmFyLCBtZWFuX2ZpdG5lc3MgPSBtZWFuX2ZpdG5lc3MsIHNkX2ZpdG5lc3MgPSBzZF9maXRuZXNzKQogIHJldHVybihyZXMpCn0pCmBgYAoKIyBHZXQgcmVmZXJlbmNlIGRhdGEKYGBge3J9CnJlZmVyZW5jZV9scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL01DMiIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCnJlZmVyZW5jZV9uYW1lLmxzIDwtIGdzdWIoIiouY3N2IiwgIiIsIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUMyLyIpLCBwYXR0ZXJuID0gIiouY3N2IikpCgojIHJlYWQgaW4gdGhlIGZpbGVzCnJlZmVyZW5jZS5scyA8LSBsYXBwbHkocmVmZXJlbmNlX2xzLCByZWFkLmNzdikKCiMgYXNzaWduIHVuaXF1ZSBJRApyZWZlcmVuY2UubHMgPC0gbWFwcGx5KGNiaW5kLCByZWZlcmVuY2UubHMsICJJRCIgPSByZWZlcmVuY2VfbmFtZS5scywgU0lNUExJRlkgPSBGKQoKIyBnZXQgbWV0YSBkYXRhCnJlZmVyZW5jZS5sczIgPC0gbWNsYXBwbHkocmVmZXJlbmNlLmxzLCBmdW5jdGlvbih4KXsKICBpZF9jb2wgPC0geCRJRAogICMgc3RyaW5nIHNwbGl0IHRvIGV4dHJhY3QgYWxsIGluZm8KICBjdWUgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1syXV0KICAjIGdldCBsb2cKICB0aGlyZF9jb2wgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1szXV0KICBsb2cgPC0gaWZlbHNlKHRoaXJkX2NvbCA9PSAibG9nIiwgImxvZzEwIiwgIm5vbmUiKQogIAogICMgZ2V0IG1lYW4KICBtZWFuX2ZpdG5lc3MgPC0gbWVhbih4JG1heF9maXRuZXNzKQogIAogICMgZ2V0IHNkCiAgc2RfZml0bmVzcyA8LSBzZCh4JG1heF9maXRuZXNzKQogIAogICMgYmluZCByZXN1bHRzCiAgcmVzIDwtIGNiaW5kKHgsIGN1ZT0gY3VlLCBsb2cgPSBsb2csIHJhbmRfdmFyID0gImFsbCIsIHJlZl9tZWFuX2ZpdG5lc3MgPSBtZWFuX2ZpdG5lc3MsIHJlZl9zZF9maXRuZXNzID0gc2RfZml0bmVzcykKICByZXR1cm4ocmVzKQp9KQpgYGAKCiMgY29tYmluZSBNQyBwYXJ0aXRpb25lZCBhbmQgcmVmZXJlbmNlIGRmCmBgYHtyfQojIGdldCB1bmlxdWUgY29sdW1uIHZhbHVlcyBmb3IgZWFjaCBjdWUsIGxvZywgYW5kIHJhbmRfdmFyIGNvbWJvCmZpdG5lc3MubHMzIDwtIGRvLmNhbGwocmJpbmQsIGZpdG5lc3MubHMyKQpmaXRuZXNzLmxzMyA8LSBmaXRuZXNzLmxzMyAlPiUgZHBseXI6OmRpc3RpbmN0KElELCAua2VlcF9hbGwgPSBUKQoKIyByZXBlYXQgd2l0aCByZWZlcmVuY2UKcmVmZXJlbmNlLmxzMyA8LSBkby5jYWxsKHJiaW5kLCByZWZlcmVuY2UubHMyKQpyZWZlcmVuY2UubHMzIDwtIHJlZmVyZW5jZS5sczMgJT4lIGRwbHlyOjpkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVCkKCiMgY29tYmluZSEKcmVmX2ZpdC5kZiA8LSBsZWZ0X2pvaW4oZml0bmVzcy5sczMsIHJlZmVyZW5jZS5sczMsIGJ5ID0gYygiY3VlIiA9ICJjdWUiLCAibG9nIj0gImxvZyIpKQpgYGAKCiMgY29tcHV0ZSBwcm9wb3J0aW9uIGZpdG5lc3MgYW5kIHZhcmlhdGlvbgpgYGB7cn0KcmVmX2ZpdC5kZjIgPC0gcmVmX2ZpdC5kZiAlPiUgCiAgbXV0YXRlKHBfc2QgPSBzZF9maXRuZXNzL3JlZl9zZF9maXRuZXNzLAogICAgICAgICBwX21lYW4gPSByZWZfbWVhbl9maXRuZXNzL21lYW5fZml0bmVzcywKICAgICAgICAgY3VlX2xvZyA9IHBhc3RlMChjdWUsICJfIiwgbG9nKSwKICAgICAgICAgbGFiZWwgPSBjYXNlX3doZW4oCiAgICAgICAgICAgY3VlID09ICJHIiB+ICJHYW1ldG9jeXRlIiwKICAgICAgICAgICBjdWUgPT0gIkkiIH4gIkFzZXh1YWwgaVJCQyIsCiAgICAgICAgICAgY3VlID09ICJJK0lnIiB+ICJBc2V4dWFsJnNleHVhbFxuaVJCQyIsCiAgICAgICAgICAgY3VlID09ICJJZyIgfiAiU2V4dWFsIGlSQkMiLAogICAgICAgICAgIGN1ZSA9PSAiUiIgfiAiUkJDIgogICAgICAgICAgICksCiAgICAgICAgIHBhcmFtZXRlciA9IGNhc2Vfd2hlbigKICAgICAgICAgICByYW5kX3Zhci54ID09ICJyaG8iIH4gIs+BIiwKICAgICAgICAgICByYW5kX3Zhci54ID09ICJwaGluIiB+ICLPlW4iLAogICAgICAgICAgIHJhbmRfdmFyLnggPT0gInBoaXcifiAiz5V3IiwKICAgICAgICAgICByYW5kX3Zhci54ID09ICJwc2luIiB+ICLPiG4iLAogICAgICAgICAgIHJhbmRfdmFyLnggPT0gInBzaXciIH4gIs+IdyIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAiYmV0YSIgfiAizrIiCiAgICAgICAgICkpCmBgYAoKIyBwbG90IQpgYGB7cn0KIyB2YXJpYXRpb24KbWNfYiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV90aWxlKGRhdGEgPSByZWZfZml0LmRmMiAsIGFlcyh4ID0gbGFiZWwsIHkgPSBwYXJhbWV0ZXIsIGZpbGwgPSBwX3NkKSkgKwogIGZhY2V0X3dyYXAofmxvZykgKwogIHRoZW1lX2J3KCkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBsYWJzKHggPSAiQ3VlIiwgeSA9ICJQYXJhbWV0ZXIgcmFuZG9taXplZCIsIGZpbGwgPSBleHByZXNzaW9uKGZyYWMoc2QoIjEgcGFyYW1ldGVyIHJhbmRvbWl6ZWQiKSwgc2QoImFsbCBwYXJhbWV0ZXJzIHJhbmRvbWl6ZWQiKSkpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQoKIyBtZWFuIGZpdG5lc3MKbWNfYyA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV90aWxlKGRhdGEgPSByZWZfZml0LmRmMiAsIGFlcyh4ID0gbGFiZWwsIHkgPSBwYXJhbWV0ZXIsIGZpbGwgPSBwX21lYW4pKSArCiAgZmFjZXRfd3JhcCh+bG9nKSArCiAgdGhlbWVfYncoKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCkgKwogIGxhYnMoeCA9ICJDdWUiLCB5ID0gIlBhcmFtZXRlciByYW5kb21pemVkIiwgZmlsbCA9IGV4cHJlc3Npb24oZnJhYyhNZWFuKCJhbGwgcGFyYW1ldGVycyByYW5kb21pemVkIiksIE1lYW4oIjEgcGFyYW1ldGVyIHJhbmRvbWl6ZWQiKSkpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQoKbWNfcGFydGl0aW9uIDwtIGdnYXJyYW5nZShtY19iLCBtY19jLCBuY29sID0gMSkKCmBgYAoKIy0tLS0tLS0tLS0tLS0tIGdldCB2aW9saW5lIHBsb3Qgb2YgdmFyaWF0aW9uIGluIGZpdG5lc3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMgcmVhZCBNQyBkYXRhCmBgYHtyfQojIHJlYWQgaW4gZHltYW1pY3MKbWNfR19sb2cuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19HX2xvZ19keW4ucGFycXVldCIpKQptY19HLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfR19keW4ucGFycXVldCIpKQptY19SX2xvZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX1JfbG9nX2R5bi5wYXJxdWV0IikpCm1jX1IuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19SX2R5bi5wYXJxdWV0IikpCm1jX0lfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSV9sb2dfZHluLnBhcnF1ZXQiKSkKbWNfSS5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lfZHluLnBhcnF1ZXQiKSkKbWNfSWdfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSWdfbG9nX2R5bi5wYXJxdWV0IikpCm1jX0lnLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSWdfZHluLnBhcnF1ZXQiKSkKbWNfSV9JZ19sb2cuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19JK0lnX2xvZ19keW4ucGFycXVldCIpKQptY19JX0lnLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19keW4ucGFycXVldCIpKQoKIyByZWFkIGluIGZpdG5lc3MKbWNfR19sb2cuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19HX2xvZ19maXRuZXNzLmNzdiIpKQptY19HLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfR19maXRuZXNzLmNzdiIpKQptY19SX2xvZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX1JfbG9nX2ZpdG5lc3MuY3N2IikpCm1jX1IuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19SX2ZpdG5lc3MuY3N2IikpCm1jX0lfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSV9sb2dfZml0bmVzcy5jc3YiKSkKbWNfSS5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lfZml0bmVzcy5jc3YiKSkKbWNfSWdfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSWdfbG9nX2ZpdG5lc3MuY3N2IikpCm1jX0lnLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSWdfZml0bmVzcy5jc3YiKSkKbWNfSV9JZ19sb2cuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19JK0lnX2xvZ19maXRuZXNzLmNzdiIpKQptY19JX0lnLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19maXRuZXNzLmNzdiIpKQpgYGAKCiMgZXhhbWluZSB2YXJpYXRpb24KYGBge3J9CiMgcGxvdCBmaXRuZXNzIHZzIGl0ZXJhdGlvbgpmaXRuZXNzLmRmIDwtIHJiaW5kKAogIGNiaW5kKG1jX0dfbG9nLmZpdG5lc3MsIGlkID0gIkdhbWV0b2N5dGVcbmxvZzEwIiksCiAgY2JpbmQobWNfRy5maXRuZXNzLCBpZCA9ICJHYW1ldG9jeXRlIiksCiAgY2JpbmQobWNfUl9sb2cuZml0bmVzcywgaWQgPSAiUkJDIGxvZzEwIiksCiAgY2JpbmQobWNfUi5maXRuZXNzLCBpZCA9ICJSQkMiKSwKICBjYmluZChtY19JX2xvZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsIGlSQkNcbmxvZzEwIiksCiAgY2JpbmQobWNfSS5maXRuZXNzLCBpZCA9ICJBc2V4dWFsIGlSQkMiKSwKICBjYmluZChtY19JZ19sb2cuZml0bmVzcywgaWQgPSAiU2V4dWFsIGlSQkNcbmxvZzEwIiksCiAgY2JpbmQobWNfSWcuZml0bmVzcywgaWQgPSAiU2V4dWFsIGlSQkMiKSwKICBjYmluZChtY19JX0lnX2xvZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsJnNleHVhbCBpUkJDXG5sb2cxMCIpLAogIGNiaW5kKG1jX0lfSWcuZml0bmVzcywgaWQgPSAiQXNleHVhbCZzZXh1YWxcbmlSQkMiKQopCgojIHF1YW50aWZ5IHZhcmlhbmNlIGFuZCBtZWFuCmZpdG5lc3NfdmFyLmRmIDwtIGZpdG5lc3MuZGYgJT4lIAogIGRwbHlyOjpncm91cF9ieShpZCkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKG1heF9maXRuZXNzKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoaWQgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihpZCwgbWVkaWFuKSkKYGBgCgojIHBsb3QgdmlvbGluIHdpdGggZGlmZmVyZW5jZSBpbiBkZXRlcm1pbmlzdGljIG1vZGVsIGZpdG5lc3MgYW5kIG1lYW4gbW9kZWwgZml0bmVzcwpgYGB7cn0KIyBnZXQgZGV0ZXJtaW5pc3RpYyBkZgpkZXQuZGYgPC0gZGF0YS5mcmFtZShmaXRuZXNzX3Zhci5kZiwgYE1heGltdW0gZml0bmVzc2AgPSAgYyg4LjQ5Nzc3LCA5LjQ5NDk5MSw4Ljg1NDY4Miw5LjU3MzI5MSw4LjU4ODU2LDkuNTYxMzczLDguMjM5OTEsOC4xODE2MDQsOC41NjkyODUsOS42MTg4MTIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShpZCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGlkLCBtZWRpYW4pKSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcigtaWQpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UobmFtZSA9PSAiTWF4aW11bS5maXRuZXNzIiwgIk9wdGltYWwgc2luZ2xlIGluZmVjdGlvbiIsICJNZWRpYW4gTW9udGUgQ2FybG8iKSkKCm1jX2EgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGRldC5kZiwgYWVzKHkgPSBpZCwgeCA9IHZhbHVlLCBzaGFwZSA9IGNsYXNzaWZpY2F0aW9uLCBjb2xvciA9IGNsYXNzaWZpY2F0aW9uKSwgc2l6ZSA9IDMpICsKICBnZW9tX3Zpb2xpbihkYXRhID0gZml0bmVzcy5kZiwgYWVzKHkgPSBpZCwgeCA9IG1heF9maXRuZXNzKSwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ3VlIiwgY29sb3IgPSAiRml0bmVzcyIsIHNoYXBlID0gIkZpdG5lc3MiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoICIjNDU3NWI0IiwgIiNmYzhkNTkiKSkKYGBgCgojLS0tLS0tLS0tLS0tLS0gcGxvdCB0b2dldGhlci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBhcnJhbmdlIHRoZSBoZWF0IG1hcApnZ2FycmFuZ2UobWNfYSwgbWNfcGFydGl0aW9uLCBoZWlnaHRzID0gYygwLjQsIDAuNiksIG5jb2wgPSAxLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkKCiMgc2F2ZQpnZ3NhdmUodW5pdHMgPSAicHgiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gMjAwMCwgZmlsZW5hbWUgPSBoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL01DLnRpZmYiKSwgYmcgPSAid2hpdGUiLCBzY2FsZSA9IDEuOCkKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIHRpbWUgc2VyaWVzIGNvbnZlcnNpb24gcmF0ZSBmb3Igc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIy0tLS0tLS0tLSBzaW5nbGUgaW5mZWN0aW9uIGNvbnZlcnNpb24gcmF0ZSBoZWF0IG1hcC0tLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgaW5mbyBmb3Igc2luZ2xlIGluZmVjdGlvbgpgYGB7cn0KIyBnZXQgZmludGVzcwpzaV9jci5kZiA8LSBzaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gImNyIikKCiMgZ29vZCBjdWUgYmFkIGN1ZQpzaV9jdWUuZHYgPC0gc2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiA5LjIgfiAiR29vZCBwZXJmb3JtaW5nIiwKICAgIHZhbHVlIDw9IDkuMiB+ICJQb29yIHBlcmZvcm1pbmciCiAgKSkKCiMgam9pbiB3aXRoIGNsYXNzaWZpY2FpdG9uCnNpX2NyLmRmMiA8LSBzaV9jci5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzaV9jdWUuZHYsIGlkLCBjbGFzc2lmaWNhdGlvbiwgZml0bmVzc19zaSA9IHZhbHVlKSwgYnkgPSAiaWQiKSAlPiUgCiAgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQoKIyBzcGxpdCBpbnRvIHRvcCBlcmZvcm1pbmcgYW5kIHBvb3ItcGVyZm9ybWluZyBjdWVzCnNpX2NyLmhpZ2ggPC0gc2lfY3IuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIkdvb2QgcGVyZm9ybWluZyIpCnNpX2NyLnBvb3IgPC0gc2lfY3IuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIlBvb3IgcGVyZm9ybWluZyIpCgpzaV9jdWUuZHYKYGBgCgojIHBsb3Qgc2luZ2xlIGluZmVjdGlvbiBjb252ZXJzaW9uIHJhdGUgaGVhdG1hcApgYGB7cn0KIyBwbG90IHBvb3IgcGVyZm9ybWluZwpzaV9jci5wbDEgPC0gZ2dwbG90KCkgKwogIGdlb21fcmFzdGVyKGRhdGEgPSBzaV9jci5wb29yLCBhZXMoeCA9IHRpbWUsIHkgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihlel9sYWJlbF9zaSwgZml0bmVzc19zaSksIGZpbGwgPSB2YWx1ZSkpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIlBvb3IgcGVyZm9ybWluZ1xuc2luZ2xlIGluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCgojIHBsb3QgaGlnaCBwZXJmb21yaW5nCnNpX2NyLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IHNpX2NyLmhpZ2gsIGFlcyh4ID0gdGltZSwgeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGV6X2xhYmVsX3NpLCBmaXRuZXNzX3NpKSwgZmlsbCA9IHZhbHVlKSkgKwogIGxhYnMoeCA9ICIiLCB5ID0gIkdvb2QgcGVyZm9ybWluZ1xuc2luZ2xlIGluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCmBgYAoKIyAtLS0tLS0tLS0tLS0tLS0tLWNvLWluZmVjdGlvbiBjb252ZXJzaW9uIHJhdGUgaGVhdG1hcC0tLS0tLS0tLS0tIwojIHBsb3QgY28taW5mZWNpdG9uIGNvbnZlc2lvbiByYXRlIGhlYXRtYXAKYGBge3J9CiMgZ2V0IGZpdGVzcwpjaV9jci5kZiA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gImNyXzEiKQoKIyBnb29kIGN1ZSBiYWQgY3VlCmNpX2N1ZS5kdiA8LSBjaV9maXRuZXNzLmRmICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBjYXNlX3doZW4oCiAgICB2YWx1ZSA+IDIuMjUgfiAiR29vZCBwZXJmb3JtaW5nIiwKICAgIHZhbHVlIDw9IDIuMjUgfiAiUG9vciBwZXJmb3JtaW5nIgogICkpCgojIGpvaW4gd2l0aCBjbGFzc2lmaWNhaXRvbgpjaV9jci5kZjIgPC0gY2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfY3VlLmR2LCBsYWJlbCwgY2xhc3NpZmljYXRpb24sIGZpdG5lc3NfY2kgPSB2YWx1ZSksIGJ5ID0gImxhYmVsIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKCiMgc3BsaXQgaW50byB0b3AgZXJmb3JtaW5nIGFuZCBwb29yLXBlcmZvcm1pbmcgY3VlcwpjaV9jci5oaWdoIDwtIGNpX2NyLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJHb29kIHBlcmZvcm1pbmciKQpjaV9jci5wb29yIDwtIGNpX2NyLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJQb29yIHBlcmZvcm1pbmciKQpgYGAKCgojIHBsb3QKYGBge3J9CiMgcGxvdCBwb29yIHBlcmZvcm1pbmcKY2lfY3IucGwxIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gY2lfY3IucG9vciwgYWVzKHggPSB0aW1lLCB5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZXpfbGFiZWwsIGZpdG5lc3NfY2kpLCBmaWxsID0gdmFsdWUpLCBhbHBoYSA9IDEpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIlBvb3IgcGVyZm9ybWluZ1xuY28taW5mZWN0aW9uIGN1ZXMiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDAsIDEpKSArCiAgeGxpbSgxLCAyMCkgKwogIHRoZW1lX2J3KCkKCiMgcGxvdCBoaWdoIHBlcmZvbXJpbmcKY2lfY3IucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gY2lfY3IuaGlnaCwgYWVzKHggPSB0aW1lLCB5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZXpfbGFiZWwsIGZpdG5lc3NfY2kpLCBmaWxsID0gdmFsdWUpLCBhbHBoYSA9IDEpICsKICBsYWJzKHggPSAiIiwgeSA9ICJHb29kIHBlcmZvcm1pbmdcbmNvLWluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCmBgYAoKIy0tLS0tLS0tLSBhc3NlbWJsZSBmaW5hbCBmaWd1cmUgLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQpzaV9jci5wbCA8LSBnZ2FycmFuZ2Uoc2lfY3IucGwyLCBzaV9jci5wbDEsIGNvbW1vbi5sZWdlbmQgPSBULCBuY29sID0gMSwgbnJvdyA9IDIpCmNpX2NyLnBsIDwtIGdnYXJyYW5nZShjaV9jci5wbDIsIGNpX2NyLnBsMSwgY29tbW9uLmxlZ2VuZCA9IFQsIG5jb2wgPSAxLCBucm93ID0gMikKCmdnYXJyYW5nZShzaV9jci5wbCwgY2lfY3IucGwsIGxhYmVscyA9IGMoIkEiLCAiQiIpLCBuY29sID0gMiwgY29tbW9uLmxlZ2VuZCA9IFQpCmdnc2F2ZSh1bml0cyA9ICJweCIsIGRwaSA9IDMwMCwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxMDAwLCBmaWxlbmFtZSA9IGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vdGltZV9jci50aWZmIiksIGJnID0gIndoaXRlIiwgc2NhbGUgPSAxLjcpCmBgYAoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIGR1YWwgY3VlIG9wdGltaXphdGlvbiBmaWd1cmUKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9oaWdoLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbi5SIikpCnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvcGFyX3RvX2htX3RlLlIiKSkKYGBgCgojLS0tLS0tLS0tLSBwbG90dGluZyBmaXRuZXNzIG9mIGR1YWwgdnMgc2luZ2xlIGN1ZSBvcHQgLS0tLS0tLS0tIwojIGltcG9ydCBpbiBwcmV2aW91cyBkYXRhCmBgYHtyfQojIGR1YWwgY3VlIGZpdG5lc3MKZHVhbF9maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZHVhbF9jdWVfb3B0NC9kdWFsX2N1ZV9maXRuZXNzXzIwLmNzdiIpKQojIyBtYWtlIGxhYmVsIGFuZCBmaWx0ZXIgb3V0IHZlcnkgbG93IGZpdG5lc3MKZHVhbF9maXRuZXNzLmRmIDwtIGR1YWxfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKHRlbXBfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbCksCiAgICAgICAgIHRlbXBfbGFiZWxfYiA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2IpLAogICAgICAgICBsYWJlbF9maW5hbCA9IHBhc3RlMCh0ZW1wX2xhYmVsLCAiKyIsIHRlbXBfbGFiZWxfYikpICU+JSAKICBmaWx0ZXIodmFsdWUgPiAyKQoKIyBnZXQgc2luZ2xlIGN1ZSBmaXRuZXNzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0iICYgdGltZSA9PSAyMCkKCiMgam9pbiBzaSBhbmQgZHVhbCBjdWUKZHVhbF9zaV9maXRuZXNzLmRmIDwtIGR1YWxfZml0bmVzcy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzaV9maXRuZXNzLmRmLCBpZCwgc2lfZml0bmVzcyA9IHZhbHVlKSwgYnkgPSAiaWQiKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzaV9maXRuZXNzLmRmLCBpZF9iID0gaWQsIHNpX2ZpdG5lc3NfYiA9IHZhbHVlKSwgYnkgPSAiaWRfYiIpICU+JSAKICBtdXRhdGUoc2lfZml0bmVzc19tYXggPSBpZmVsc2Uoc2lfZml0bmVzcyA+IHNpX2ZpdG5lc3NfYiwgc2lfZml0bmVzcywgc2lfZml0bmVzc19iKSwKICAgICAgICAgZHVhbF9sYWJlbCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIHBhc3RlKGxhYmVsLCAiKyIsIGxhYmVsX2IpKSkKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfc2lfZml0bmVzcy5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9zaV9maXRuZXNzLmRmLCBhZXMoeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGR1YWxfbGFiZWwsIHZhbHVlKSwgeCA9IHZhbHVlLCBjb2xvciA9ICJEdWFsIGN1ZSIsIHNoYXBlID0gIkR1YWwgY3VlIiksIHNpemUgPSAzLCBhbHBoYSA9IDAuNykgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfc2lfZml0bmVzcy5kZiwgYWVzKHkgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihkdWFsX2xhYmVsLCB2YWx1ZSksIHggPSBzaV9maXRuZXNzX21heCwgY29sb3I9ICJCZXN0IHNpbmdsZSBjdWUiLCBzaGFwZT0gIkJlc3Qgc2luZ2xlIGN1ZSIpLCBzaXplID0gMywgYWxwaGEgPSAwLjcpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiRHVhbCBjdWUiLCBjb2xvciA9ICJDdWUiLCBzaGFwZSA9ICJDdWUiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjZmM4ZDU5IiwgIiM0NTc1YjQiKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkuODgzNjAyKSArCiAgZ2VvbV90ZXh0KGFlcyh4PTkuODgzNjAyLCBsYWJlbD0iXG5JZGVhbCBmaXRuZXNzIChkZj05KSIsIHkgPSAiRyArIFIgbG9nMTAiKSwgYW5nbGU9OTApICsKICB0aGVtZV9idygpCmBgYAoKCiMtLS0tLS0tLS0tLSB0aW1lIHNlcmllcyBjb252ZXJzaW9uIHJhdGUgLS0tLS0tLS0tLS0tLSMKIyBkeW5hbWljcyBzaW11bGF0aW9uIG9mIGhpZ2ggcGFyYW1ldGVyIGN1ZXMgKHRoZXNlIHNlcnZlIGFzIHJlZmVyZW5jZSBwb2ludHMpCmBgYHtyfQojIGJlc3QgZHVhbCBjdWUgY29tYm8KZHVhbC5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg0LjQ0NjE5MjAzMywJMTAuOTc1MTgyNzUsCTEuMzg3NjI4MTcsCTIzLjMwNTkyNTQsCS0zLjQ1MjA1MjM3MSwJLTE4LjAwNzA2OTIsCTM5LjY2NjE0MjI2LAktMy41NDUxOTMxNDEsCTE4Ljc4MzUwNzk5KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDYsIDcsIGJ5ID0gMS81MDApLAogIGN1ZV9yYW5nZV9iID0gc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDApLAogIGN1ZSA9ICJSIiwKICBjdWVfYiA9ICJJIiwKICBsb2dfY3VlID0gImxvZzEwIiwKICBsb2dfY3VlX2IgPSAibG9nMTAiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUCikKCiMgd2hlbiB0aW1lIGlzIHVzZWQgYXMgYSBjdWUgKGhpZ2ggcGFyYW1ldGVyKQp0aW1lLmNyIDwtIGNoYWJhdWRpX3NpX2NsZWFuX2hpZ2goCiAgcGFyYW1ldGVyc19jciA9IGMoOS4xNTQzMTQsICAtNy41NzA4MjksIC0yMi41MDY2MzggLCAgMy4zODI0MDUgLC0xMy40NTM1MTkgLC0xNy4wMTE0ODUgICwgMy42NzgxODEsIC0xMi44NTE4OTUgLC0yNi4xMTUxNTgpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlID0gInQiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyB3aGVuIGFzZXh1YWwgaVJCQyBpcyB1c2VkIGFzIGEgY3VlIChoaWdoIGZsZXhpYmlsaXR5KQpJX2hpZ2guY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW5faGlnaCgKICBwYXJhbWV0ZXJzX2NyID0gYygxLjI5NjY3NSwgIDMuNTQ0MDM0ICwgNC45MDc0ODQsICAyLjE3NDI0OSwgLTMuMjM4MzA5ICwtNS4xODE2MTQgLC0xLjY0NTA3MiAsIDEuODM0MzAyICwgMS41ODEwMTEpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoMCwgbG9nMTAoNiooMTBeNikpLCBieSA9IChsb2cxMCg2KigxMF42KSkpLzUwMDApLAogIGN1ZSA9ICJJIiwKICBsb2dfY3VlID0gImxvZzEwIiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVCkKCiMgd2hlbiBhc2V4dWFsIGlSQkMgaXMgdXNlZCBhcyBhIGN1ZSAobm9ybWFsIGZsZXhpYmlsaXR5KQpJLmNyIDwtIGNoYWJhdWRpX3NpX2NsZWFuKAogIHBhcmFtZXRlcnNfY3IgPSBjKDUuNDYzNTU4LAkyLjM4Mzk0OCwJLTE3Ljc1NzI4MSwJNC41NzE4MzUpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoMCwgbG9nMTAoNiooMTBeNikpLCBieSA9IChsb2cxMCg2KigxMF42KSkpLzUwMDApLAogIGN1ZSA9ICJJIiwKICBsb2dfY3VlID0gImxvZzEwIiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVCkKCiMgcHJvY2VzcyAKSV9oaWdoLmNyMiA8LSBJX2hpZ2guY3IgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKSAlPiUgbXV0YXRlKGxhYmVsX25ldyA9ICJJIGxvZzEwIChkZj05KSIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKSS5jcjIgPC0gSS5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIkkgbG9nMTAgKGRmPTMpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgp0aW1lX2hpZ2guY3IyIDwtIHRpbWUuY3IgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKSAlPiUgbXV0YXRlKGxhYmVsX25ldyA9ICJJZGVhbCAoZGY9OSkiKSAlPiUgc2VsZWN0KC12YXJpYWJsZSkKCmR1YWwuY3IyIDwtIGR1YWwuY3IgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKSAlPiUgbXV0YXRlKGxhYmVsX25ldyA9ICJSIGxvZzEwICsgSSBsb2cxMCAoZGY9OSkiKSAlPiUgc2VsZWN0KC12YXJpYWJsZSkKCiMgY29tYmluZQpkdWFsX2NyLmRmIDwtIHJiaW5kKElfaGlnaC5jcjIsIEkuY3IyLCB0aW1lX2hpZ2guY3IyLCBkdWFsLmNyMikKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfY3IucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbF9jci5kZiwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmRmICU+JSBmaWx0ZXIodGltZSUlMSA9PSAwKSwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlLCBzaGFwZSA9IGxhYmVsX25ldyksIHNpemUgPSAzKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDdWUiLCBzaGFwZSA9ICJDdWUiKSArCiAgeGxpbSgwLCAyMCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmM4ZDU5IiwiI2ZkY2I0NCIsImJsYWNrIiwgIiM0NTc1YjQiKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgYnlyb3cgPSBUUlVFKSkKYGBgCgojLS0tLS0tLS0tLS0tIHJlYWN0aW9uIG5vcm0gaGVhdG1hcCBvZiBSIGxvZzEwICsgSSBsb2cxMCAtLS0tLS0tLS0tLS0jCiMgcHJvY2VzcyBkYXRhCmBgYHtyfQojIG1ha2UgaGVhdG1hcCBkZgpSX0kuaG0gPC0gcGFyX3RvX2htX3RlKHBhciA9IGMoNC40NDYxOTIwMzMsCTEwLjk3NTE4Mjc1LAkxLjM4NzYyODE3LAkyMy4zMDU5MjU0LAktMy40NTIwNTIzNzEsCS0xOC4wMDcwNjkyLAkzOS42NjYxNDIyNiwJLTMuNTQ1MTkzMTQxLAkxOC43ODM1MDc5OSksCiAgICAgICAgICAgICBjdWVfcmFuZ2UgPSBzZXEoNiwJNywgbGVuZ3RoLm91dCA9IDUwMCksCiAgICAgICAgICAgICBjdWVfcmFuZ2VfYiA9IHNlcSgwLAk2Ljc3ODE1MTI1LCBsZW5ndGgub3V0ID0gNTAwKSkKCiMgcHJvY2VzcyBkeW5hbWljcwpSX0kuZHluIDwtIGR1YWwuY3IgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUpICU+JSAKICBtdXRhdGUobG9nX1IgPSBsb2cxMChSKSwKICAgICAgICAgbG9nX0kgPSBsb2cxMChJKSkKCiMgZXhhbWluZSBzZXh1YWwgaVJCQyBhcyB3ZWxsClJfSWcuZHluIDwtIGR1YWwuY3IgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUpICU+JSAKICBtdXRhdGUobG9nX1IgPSBsb2cxMChSKSwKICAgICAgICAgbG9nX0lnID0gbG9nMTAoSWcpKQptYXgoUl9JZy5keW4kSWcpIApgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9ybi5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IFJfSS5obSwgYWVzKHggPSBjdWVfcmFuZ2VfYiwgeSA9IGN1ZV9yYW5nZSwgZmlsbCA9IGNyKSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIGdlb21fcGF0aChkYXRhID0gUl9JLmR5biwgYWVzKHggPSBsb2dfSSwgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiLCBhcnJvdyA9IGFycm93KGFuZ2xlID0gMzAsIGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gUl9JLmR5biAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09IDEgJiB0aW1lIDw9IDIwKSwgYWVzKHggPSBsb2dfSSwgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiKSArCiAgeGxpbSgwLjk5Km1pbihoYWJsYXI6OnMoUl9JLmR5biRsb2dfSSksIG5hLnJtID0gVCksIDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfSSksIG5hLnJtID0gVCkpICsKICB5bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19SKSwgbmEucm0gPSBUKSwxLjAxKiBtYXgoaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpKSArCiAgbGFicyh5ID0gIlJCQyBsb2cxMCIsIHggPSAiQXNleHVhbCBpUkJDIGxvZzEwIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWVfZGFyaygpCgojIGp1c3QgdGVzdGluZyBmb3Igc2V4dWFsIGlSQkMgdnMgUkJDCmdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IFJfSWcuZHluLCBhZXMoeCA9IElnLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIsIGFycm93ID0gYXJyb3coYW5nbGUgPSAzMCwgbGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBSX0lnLmR5biAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09IDEgJiB0aW1lIDw9IDIwKSwgYWVzKHggPSBJZywgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikgKwogIHhsaW0oMCwgMjAwMDAwKSArCiAgbGFicyh5ID0gIlJCQyBsb2cxMCIsIHggPSAiU2V4dWFsIGlSQkMgbG9nMTAiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9kYXJrKCkKYGBgCgojIHNhdmUgZmlndXJlIGZvciBwb3N0ZXIKYGBge3J9CmR1YWxfcm4ucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gUl9JLmhtLCBhZXMoeCA9IGN1ZV9yYW5nZV9iLCB5ID0gY3VlX3JhbmdlLCBmaWxsID0gY3IpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0kuZHluLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIsIGFycm93ID0gYXJyb3coYW5nbGUgPSAzMCwgbGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBSX0kuZHluICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0gMSAmIHRpbWUgPD0gMjApLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICB4bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSwgMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSkgKwogIHlsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpLDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCkpICsKICBsYWJzKHkgPSAiUkJDIGxvZzEwIiwgeCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9kYXJrKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpIAoKZHVhbF9jci5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbF9jci5kZiwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmRmICU+JSBmaWx0ZXIodGltZSUlMSA9PSAwKSwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlLCBzaGFwZSA9IGxhYmVsX25ldyksIHNpemUgPSAyKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDdWUiLCBzaGFwZSA9ICJDdWUiKSArCiAgeGxpbSgwLCAyMCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNDU3NWI0IiwgIiM5MWJmZGIiLCIjZmM4ZDU5IiwiI2ZkY2I0NCIpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpKQoKZ2dhcnJhbmdlKGR1YWxfY3IucGwyLCBkdWFsX3JuLnBsMiwgYWxpZ24gPSAiaCIsIHdpZHRocyA9IGMoMS4yNSwgMSkpCmdnc2F2ZShoZXJlKCJwb3N0ZXIvZHVhbF9jdWUucG5nIiksIHdpZHRoID0gNywgaGVpZ2h0ID0gNCkKYGBgCgoKIy0tLS0tLS0tIGFzc2VtYmxlIGZpbmFsIGZpZ3VyZSAtLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBhc3NlbWJsZSBwYW5lbCBCIGFuZCBDCmR1YWxfcGwuQkMgPC0gZ2dhcnJhbmdlKGR1YWxfY3IucGwsIGR1YWxfcm4ucGwsIGFsaWduID0gInYiLCBuY29sID0gMSwgbGFiZWxzID0gYygiQiIsICJDIikpCgojIGFzc2VtYmxlIHBhbmVsIEEKZ2dhcnJhbmdlKGR1YWxfc2lfZml0bmVzcy5wbCwgZHVhbF9wbC5CQywgbmNvbCA9IDIsIGxhYmVscyA9IGMoIkEiLCAiIiksIHdpZHRocyA9IGMoMSwgMC43NSkpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2R1YWxfY3VlLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDE0MDAsIHNjYWxlID0gMS41LCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgcmVhbCBsaWZlIGRpc2Vhc2UgY3VydmUKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGV4ZWN1dGUgY29kZSBmcm9tIHJlcG9ydCAxMCB0byBnZXQgZmluYWwgZGF0YXNldApUaGUgZm9sbG93aW5nIGdyYXBocyB3aWxsIGJlIG1hZGU6Ci0gUiB2cyBpUkJDCi0gUiBsb2cxMCB2cyBpUkJDCi0gUiB2cyBpUkJDIGxvZzEwCi0gUiBsb2cxMCB2cyBpUkJDIGxvZzEwCgotIEcgdnMgaVJCQwotIEcgbG9nMTAgdnMgaVJCQwotIEcgdnMgaVJCQyBsb2cxMAotIEcgbG9nMTAgdnMgaVJCQyBsb2cxMAoKLSBSIHZzIEcKLSBSIGxvZzEwIHZzIEcKLSBSIHZzIEcgbG9nMTAKLSBSIGxvZzEwIHZzIEcgbG9nMTAKClIgb24geS1heGlzCmBgYHtyfQpyX2kuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBSQkMsIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IFJCQywgeCA9IGFzZXgsIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiaVJCQyBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcmxvZ19pLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGFzZXgpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGFzZXgsIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiaVJCQyBwZXIgwrVMIiwgeSA9ICJsb2cxMChSQkMpIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJfaWxvZy5kYyA8LWdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gUkJDLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gUkJDLCB4ID0gbG9nMTAoYXNleCksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoaVJCQykgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJsb2dfaWxvZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBsb2cxMChhc2V4KSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gbG9nMTAoYXNleCksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoaVJCQykgcGVyIMK1TCIsIHkgPSAibG9nMTAoUkJDKSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCmBgYAoKRyBvbiB5LWF4aXMKYGBge3J9CmdfaS5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGdhbSwgeCA9IGFzZXgpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gZ2FtLCB4ID0gYXNleCwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJpUkJDIHBlciDCtUwiLCB5ID0gIkdhbWV0b2N5dGUgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKZ2xvZ19pLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoZ2FtKSwgeCA9IGFzZXgpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoZ2FtKSwgeCA9IGFzZXgsIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiaVJCQyBwZXIgwrVMIiwgeSA9ICJsb2cxMChHYW1ldG9jeXRlKSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpnX2lsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBnYW0sIHggPSBsb2cxMChhc2V4KSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBnYW0sIHggPSBsb2cxMChhc2V4KSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJsb2cxMChpUkJDKSBwZXIgwrVMIiwgeSA9ICJHYW1ldG9jeXRlIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCmdsb2dfaWxvZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKGdhbSksIHggPSBsb2cxMChhc2V4KSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChnYW0pLCB4ID0gbG9nMTAoYXNleCksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoaVJCQykgcGVyIMK1TCIsIHkgPSAibG9nMTAoR2FtZXRvY3l0ZSkgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQpgYGAKClIgdnMgRwpgYGB7cn0Kcl9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gUkJDLCB4ID0gZ2FtKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IFJCQywgeCA9IGdhbSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJHYW1ldG9jeXRlIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpybG9nX2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gZ2FtKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBnYW0sIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiR2FtZXRvY3l0ZSBwZXIgwrVMIiwgeSA9ICJsb2cxMChSQkMgcGVyIMK1TCkiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJfZ2xvZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGdhbSkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gUkJDLCB4ID0gbG9nMTAoZ2FtKSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJsb2cxMChHYW1ldG9jeXRlKSBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcmxvZ19nbG9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGxvZzEwKGdhbSkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGxvZzEwKGdhbSksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoR2FtZXRvY3l0ZSkgcGVyIMK1TCIsIHkgPSAibG9nMTAoUkJDKSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCmBgYAoKIyBwbG90IHRvZ2V0aGVyCmBgYHtyfQpnZ2FycmFuZ2Uocl9pLmRjLCBybG9nX2kuZGMsIHJfaWxvZy5kYywgcmxvZ19pbG9nLmRjLAogICAgICAgICAgZ19pLmRjLCBnbG9nX2kuZGMsIGdfaWxvZy5kYywgZ2xvZ19pbG9nLmRjLAogICAgICAgICAgcl9nLmRjLCBybG9nX2cuZGMsIHJfZ2xvZy5kYywgcmxvZ19nbG9nLmRjLCAKICAgICAgICAgIG5jb2wgPSA0LCBucm93ID0gMywgYWxpZ24gPSAiaHYiLCBjb21tb24ubGVnZW5kID0gVCkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZXhwX2Rpc2Vhc2UtY3VydmUudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTUwMCwgc2NhbGUgPSAyLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIHN0YXRpYyBjb21wZXRpdGlvbgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIy0tLS0tLS0gaGVhdCBtYXAgLS0tLS0tLS0tLS0tLS0tIwojIGNhbGN1bGF0ZSBmaXRuZXNzIGRpZmZlcmVuY2UgZm9yIDIwIGRheXMKYGBge3J9CiMgZ2V0IGR5bmFtaWNzCnN0YXRpYy5scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL2NpX3N0YXRpYy8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKc3RhdGljLmxzIDwtIGxhcHBseShzdGF0aWMubHMsIHJlYWRfcGFycXVldCkKCiMgZ2V0IGZpdG5lc3MgYXQgZGF5IDIwIChvcHRpbWl6ZWQgZm9yIDIwIGRheXMpCnN0YXRpY19maXRuZXNzLmxzIDwtIG1jbGFwcGx5KHN0YXRpYy5scywgZnVuY3Rpb24oeCl7CiAgeCAlPiUgZmlsdGVyKHRpbWUgPT0gMjAgJiB2YXJpYWJsZSAlaW4lIGMoInRhdV9jdW0xIiwgInRhdV9jdW0yIikpCn0pCnN0YXRpY19maXRuZXNzLmRmIDwtIGRvLmNhbGwocmJpbmQsIHN0YXRpY19maXRuZXNzLmxzKQoKc3RhdGljX2ZpdG5lc3MuZGYgPC0gdGlkeXI6OnBpdm90X3dpZGVyKHN0YXRpY19maXRuZXNzLmRmLCBuYW1lc19mcm9tID0gInZhcmlhYmxlIiwgaWRfY29scyA9IGMoImlkXzEiLCAiaWRfMiIpKSAlPiUgCiAgZ3JvdXBfYnkoaWRfMSwgaWRfMikgJT4lIAogIG11dGF0ZShmaXRuZXNzX2RpZmZlcmVuY2UgPSB0YXVfY3VtMS10YXVfY3VtMikKd3JpdGUuY3N2KHN0YXRpY19maXRuZXNzLmRmLCBoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKYGBgCgojIGltcG9ydCBhbmQgcHJvY2VzcyBkYXRhCmBgYHtyfQojIGltcG9ydCBpbiBkYXRhc2V0CnN0YXRpYy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKZXpfbGFiZWwgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9lel9sYWJlbC5jc3YiKSkKCiMgam9pbiB3aXRoIGxhYmVsbGluZwpzdGF0aWMuZGYyIDwtIHN0YXRpYy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGxhYmVsX2NpXzEgPSBsYWJlbF9jaSksIGJ5ID0gYygiaWRfMSIgPSAiaWRfY2kiKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaV8yID0gbGFiZWxfY2kpLCBieSA9IGMoImlkXzIiID0gImlkX2NpIikpICU+JSAKICBzZWxlY3QobGFiZWxfY2lfMSwgbGFiZWxfY2lfMiwgZml0bmVzc19kaWZmZXJlbmNlKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2NpXzEgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbF9jaV8xKSwKICAgICAgICAgbGFiZWxfY2lfMiA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2NpXzIpKQoKIyBnZXQgcmV2ZXJzZSBvcmRlciwgd2hpY2ggaXMgc2ltcGx5IGludm92bGVzIHN3aXRjaGluZyB0aGUgY3VlcyBhcm91bmQgdGhlIG11bHRpcGx5aW5nIHRoZSBmaXRuZXNzIGJ5IG5lZ2F0aXZlIDEKc3RhdGljLmRmMyA8LSBzdGF0aWMuZGYyCm5hbWVzKHN0YXRpYy5kZjMpIDwtIGMoImxhYmVsX2NpXzIiLCAibGFiZWxfY2lfMSIsICJmaXRuZXNzX2RpZmZlcmVuY2UiKQpzdGF0aWMuZGYzJGZpdG5lc3NfZGlmZmVyZW5jZSA8LSBzdGF0aWMuZGYyJGZpdG5lc3NfZGlmZmVyZW5jZSAqIC0xCgojIGpvaW4Kc3RhdGljLmRmNCA8LSByYmluZChzdGF0aWMuZGYyLCBzdGF0aWMuZGYzKQoKIyBnZXQgbWVhbgpzdGF0aWMubWVhbiA8LSBzdGF0aWMuZGY0ICU+JSAKICBkaXN0aW5jdChsYWJlbF9jaV8xLCBsYWJlbF9jaV8yLCAua2VlcF9hbGwgPSBUKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2lfMSkgJT4lIAogIHN1bW1hcml6ZShtZWFuX2ZpdG5lc3MgPSBtZWFuKGZpdG5lc3NfZGlmZmVyZW5jZSwgbmEucm0gPSBUKSkKICAKCiMgam9pbiBzdGF0aWMuZGY0IHdpdGggbWVhbiBmb3Igb3JkZXIgc29ydGluZwpzdGF0aWMuZGY1IDwtIHN0YXRpYy5kZjQgJT4lIAogIGxlZnRfam9pbihzdGF0aWMubWVhbiwgYnkgPSAibGFiZWxfY2lfMSIpICU+JSAKICBtdXRhdGUobGFiZWxfY2lfMSA9IGZjdF9yZW9yZGVyKGxhYmVsX2NpXzEsIG1lYW5fZml0bmVzcyksCiAgICAgICAgIGxhYmVsX2NpXzIgPSBmY3RfcmVsZXZlbChsYWJlbF9jaV8yLCBsZXZlbHMoc3RhdGljLmRmNSRsYWJlbF9jaV8xKSkpCmBgYAoKIyBwbG90CmBgYHtyfQojIGhlYXRtYXAKc3RhdGljLnBsMSA8LSBnZ3Bsb3QoZGF0YSA9IHN0YXRpYy5kZjUsIGFlcyh4ID0gbGFiZWxfY2lfMiwgeSA9IGxhYmVsX2NpXzEsIG1lYW5fZml0bmVzcywgZmlsbCA9IGZpdG5lc3NfZGlmZmVyZW5jZSkpKwogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiI2ZjOGQ1OSIsIGhpZ2ggPSAiIzQ1NzViNCIsIG1pZCA9ICJ3aGl0ZSIsIAogICBtaWRwb2ludCA9IDAsIHNwYWNlID0gIkxhYiIsIGxpbSA9IGMoLTAuOTUsIDAuOTUpLCBuYW1lPSJGaXRuZXNzXG5kaWZmZXJlbmNlIikgKwogIHRoZW1lX21pbmltYWwoKSArICAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibGVmdCIsCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAxLCBoanVzdCA9IDEpLAogIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgcGxvdC5tYXJnaW49bWFyZ2luKHIgPSAtMSwgbCA9IC0xLCB1bml0ID0gInB0IikpICsgCiAgbGFicyh4ID0gIlN0cmFpbiAyIGN1ZSIsIHkgPSAiU3RyYWluIDEgY3VlIikgKwogIGNvb3JkX2ZpeGVkKCkKCiMgbWVhbiAKc3RhdGljLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoZGF0YSA9ICBzdGF0aWMubWVhbiwgYWVzKHkgPSBmY3RfcmVvcmRlcihsYWJlbF9jaV8xLCBtZWFuX2ZpdG5lc3MpLCB4ID0gbWVhbl9maXRuZXNzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBsYWJzKHkgPSAiIiwgeCA9ICJNZWFuIGZpdG5lc3NcbmRpZmZlcmVuY2UiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4obCA9IDApLAogICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpCgpnZ2FycmFuZ2Uoc3RhdGljLnBsMSwgc3RhdGljLnBsMiwgYWxpZ24gPSAiaHYiLCB3aWR0aHMgPSBjKDEsIDAuMikpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3N0YXRpY19jb21wZXRpdGlvbl9hLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDE1MDAsIHNjYWxlID0gMS4yLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCiMtLS0tLS0gZWZmZWN0IGN1ZSBwZXJjZXB0aW9uIC0tLS0tLS0jCiMjIGxvZ2dpbmcKYGBge3J9CiMgZ2V0IG5vbi1sb2dnZWQgcGFpcmluZ3MKc3RhdGljX25vbG9nIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJub25lIikKCnN0YXRpY19sb2cgPC0gc3RhdGljLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gdHJpbXdzKGdzdWIoIlxcIC4qIiwgIiIsIGxhYmVsX2NpXzEpKSwKICAgICAgICAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIikpICU+JSAKICBmaWx0ZXIobG9nXzEgPT0gImxvZyIpCgpzdGF0aWNfbG9nLmRmIDwtIGxlZnRfam9pbigKICBzZWxlY3Qoc3RhdGljX25vbG9nLCBjdWVfMSwgbGFiZWxfY2lfMiwgbG9nXzEsIE5vbmUgPSBmaXRuZXNzX2RpZmZlcmVuY2UpLAogIHNlbGVjdChzdGF0aWNfbG9nLCBjdWVfMSwgbGFiZWxfY2lfMiwgbG9nXzEsIExvZyA9IGZpdG5lc3NfZGlmZmVyZW5jZSksCiAgYnkgPSBjKCJjdWVfMSIsICJsYWJlbF9jaV8yIikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKE5vbmUpICYgIWlzLm5hKExvZykpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoTG9nID4gTm9uZSwgIkxvZ2dlZCBiZXR0ZXIiLCAiTm90IGxvZ2dlZCBiZXR0ZXIiKSkKYGBgCgojIGNvbWJpbmVkCmBgYHtyfQpzdGF0aWNfbm9jb21iIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gIm5vbmUiKQoKc3RhdGljX2NvbWIgPC0gc3RhdGljLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gaWZlbHNlKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAic3VtIiksICJJK0lnIiwKICAgIHRyaW13cyhnc3ViKCIrMS4qfFxcIGxvZyIsICIiLCBsYWJlbF9jaV8xKSkKICApLAogIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpLAogICAgY29tYl8xID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIikgfiAiY29tYiIsCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iLCBuZWdhdGUgPSBUKSB+ICJub25lIiAKICApKSAlPiUgCiAgZmlsdGVyKGNvbWJfMSA9PSAiY29tYiIpCiAgCnN0YXRpY19jb21iLmRmIDwtIGxlZnRfam9pbigKICBzZWxlY3Qoc3RhdGljX25vY29tYiwgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBTZWxmID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBzZWxlY3Qoc3RhdGljX2NvbWIsIGN1ZV8xLCBsYWJlbF9jaV8yLCBsb2dfMSwgVG90YWwgPSBmaXRuZXNzX2RpZmZlcmVuY2UpLAogIGJ5ID0gYygiY3VlXzEiLCAibG9nXzEiLCAibGFiZWxfY2lfMiIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShUb3RhbCkgJiAhaXMubmEoU2VsZikpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoVG90YWwgPiBTZWxmLCAiVG90YWwgYmV0dGVyIiwgIlNlbGYgYmV0dGVyIikpCmBgYAoKIyBwbG90CmBgYHtyfQpzdGF0aWNfbG9nLnBsIDwtIGdncGFpcmVkKHN0YXRpY19sb2cuZGYsIGNvbmQxID0gIk5vbmUiLCBjb25kMiA9ICJMb2ciLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHggPSAiQ3VlIHBlcmNlcHRpb24iLCB5ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSIsIGNvbG9yID0gIkVmZmVjdCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTm90IGxvZ2dlZCBiZXR0ZXIiID0gIiNmYzhkNTkiLCAiTG9nZ2VkIGJldHRlciIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gLTAuMSkKCnN0YXRpY19jb21iLnBsIDwtIGdncGFpcmVkKHN0YXRpY19jb21iLmRmLCBjb25kMSA9ICJUb3RhbCIsIGNvbmQyID0gIlNlbGYiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHggPSAiQ3VlIHBlcmNlcHRpb24iLCB5ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSIsIGNvbG9yID0gIkVmZmVjdCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVG90YWwgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIlNlbGYgYmV0dGVyIiA9ICIjNDU3NWI0IikpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAtMC4yKQoKZ2dhcnJhbmdlKHN0YXRpY19sb2cucGwsIHN0YXRpY19jb21iLnBsLCBuY29sID0gMSwgbnJvdyA9IDIsIGFsaWduID0gInYiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9zdGF0aWNfY29tcGV0aXRpb25fYi50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSAyMDAwLCBzY2FsZSA9IDEuMiwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgaW52YXNpb24gYW5hbHlzaXMKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgaW1wb3J0IGluIGRhdGEgKGFscmVhZHkgMjAgZGF5cyApCmBgYHtyfQppbnZhZGUuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKYGBgCgoKIyBwcm9jZXNzIGRhdGEgZm9yIGludmFzaW9uIG1hdHJpeApgYGB7cn0KaW52YWRlLm1hdCA8LSBpbnZhZGUuZGYgJT4lIAogIGdyb3VwX2J5KFYxID0gcG1pbihtdXRfaWQsIHJlc19pZCksIFYyID0gcG1heChtdXRfaWQsIHJlc19pZCkpICU+JSAjIGdyb3VwIGJ5IGN1ZSBjb21wZXRpdGlvbiwgaXJyZWdhcmRsZXNzIG9mIG9yZGVyCiAgbXV0YXRlKGlkX2FsdCA9IHBhc3RlMChWMSwgVjIpLAogICAgICAgICBpbnZhZGUgPSBjYXNlX3doZW4oCiAgICAgICAgICAgZml0bmVzcyA+IDAgfiAiaW52YWRlIiwKICAgICAgICAgICBmaXRuZXNzIDwgMCB+ICJub3QgaW52YWRlIgogICAgICAgICApKSAlPiUgCiAgZ3JvdXBfYnkoaWRfYWx0KSAlPiUgCiAgbXV0YXRlKAogICAgbXV0X2lzX1YxID0gY2FzZV93aGVuKAogICAgbXV0X2lkID09IFYxIH4gIlYxX2ludmFkZSIsCiAgICBtdXRfaWQgIT0gVjEgfiAiVjFfaW52YWRlZCIpKSAlPiUgCiAgYXJyYW5nZShpZF9hbHQpICU+JSAKICBzZWxlY3QoZml0bmVzcywgVjEsIFYyLCBpZF9hbHQsIGludmFkZSwgbXV0X2lzX1YxKSAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBtdXRfaXNfVjEsIHZhbHVlc19mcm9tID0gZml0bmVzcykgJT4lIAogIGdyb3VwX2J5KGlkX2FsdCkgJT4lIAogIG11dGF0ZShWMV9pbnZhZGUyID0gZ3N1YigiTkEiLCAiIiwgcGFzdGUwKFYxX2ludmFkZSwgY29sbGFwc2UgPSAiIikpLAogICAgICAgICBWMV9pbnZhZGVkMiA9IGdzdWIoIk5BIiwgIiIsIHBhc3RlMChWMV9pbnZhZGVkLCBjb2xsYXBzZSA9ICIiKSkpICU+JSAKICBkaXN0aW5jdChpZF9hbHQsIC5rZWVwX2FsbCA9IFQpICU+JSAKICBtdXRhdGUoCiAgICBjYXRlZ29yeSA9IGNhc2Vfd2hlbigKICAgIFYxX2ludmFkZTIgPiAwICYgVjFfaW52YWRlZDIgPiAwIH4gIk11dHVhbCBpbnZhc2lvbiIsCiAgICBWMV9pbnZhZGUyID4gMCAmIFYxX2ludmFkZWQyIDwgMCB+ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiwKICAgIFYxX2ludmFkZTIgPCAwICYgVjFfaW52YWRlZDIgPiAwIH4gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iLAogICAgVjFfaW52YWRlMiA8IDAgJiBWMV9pbnZhZGVkMiA8IDAgfiAiTXV0dWFsIG5vbi1pbnZhc2lvbiIKICApKSAlPiUgCiAgc2VsZWN0KFYxLCBWMiwgaW52YXNpb24gPSBjYXRlZ29yeSkKCmludmFkZS5kZiAlPiUgZmlsdGVyKG11dF9pZCA9PSAiRy1pX25vbmUiKQppbnZhZGUuZGYgJT4lIGZpbHRlcihyZXNfaWQgPT0gIkctaV9ub25lIikKYGBgCgoKYGBge3J9CiMgZm9yIHBsb3R0aW5nLCBuZWVkIHRvIGdldCBhbGwgc2FtZSBjdWUgdnMgc2FtZSBjdWUsIHdoaWNoIHdlIHdpbGwgc2V0IHRvIE5BCmludmFkZS5OQSA8LSBjYmluZC5kYXRhLmZyYW1lKGBWMWAgPSB1bmlxdWUoaW52YWRlLm1hdCRWMSksCiAgICAgIGBWMmAgPSB1bmlxdWUoaW52YWRlLm1hdCRWMSksCiAgICAgIGludmFzaW9uID0gTkEpCgppbnZhZGUubWF0MiA8LSByYmluZChpbnZhZGUubWF0LCBpbnZhZGUuTkEpCgojIGdldCBsYWJlbAppbnZhZGUubWF0MyA8LSBpbnZhZGUubWF0MiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIFYxX2xhYmVsID0gbGFiZWxfY2kpLCBieSA9IGMoIlYxIiA9ICJpZF9jaSIpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIFYyX2xhYmVsID0gbGFiZWxfY2kpLCBieSA9IGMoIlYyIiA9ICJpZF9jaSIpKSAlPiUgCiAgbXV0YXRlKFYxX2xhYmVsID0gZ3N1YigibG9nIiwgImxvZzEwIiwgVjFfbGFiZWwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFYyX2xhYmVsID0gZ3N1YigibG9nIiwgImxvZzEwIiwgVjJfbGFiZWwpKQoKCmludmFkZS5tYXQ0IDwtIHJiaW5kKAogIHNlbGVjdChpbnZhZGUubWF0MywgVjFfbGFiZWwsIFYyX2xhYmVsLCBpbnZhc2lvbiksCiAgc2VsZWN0KGludmFkZS5tYXQzLCBWMl9sYWJlbCA9IFYxX2xhYmVsLCBWMV9sYWJlbCA9IFYyX2xhYmVsKSAlPiUgbXV0YXRlKGludmFzaW9uID0gTkEpKSAlPiUKICBtdXRhdGUoCiAgICBpbnZhc2lvbl8yID0gY2FzZV93aGVuKAogICAgaW52YXNpb24gPT0gIk11dHVhbCBpbnZhc2lvbiIgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiB+ICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbm9mIGFub3RoZXIgY3VlIiwKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiB+ICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbmJ5IGFub3RoZXIgY3VlIgogICkpICU+JSAKICBmaWx0ZXIoIWlzLm5hKFYxX2xhYmVsKSkKCmludmFkZS5tYXQ0JFYxX2xhYmVsIDwtIGZhY3RvcihpbnZhZGUubWF0NCRWMV9sYWJlbCwgbGV2ZWxzID0gIGMoIkcgbG9nMTAiLCAiRyIsICJHMStHMiIsICJJIGxvZzEwIiwgIkkiLCAiSStJZyBsb2cxMCIsICJJK0lnIiwgIkkxK0kyIGxvZzEwIiwgIkkxK0kyIiwgIklnIGxvZzEwIiwgIklnIiwgIklnMStJZzIiLCAiUiBsb2cxMCIsICJSIiwgInN1bSBsb2cxMCIsICJzdW0iKSkKaW52YWRlLm1hdDQkVjJfbGFiZWwgPC0gZmFjdG9yKGludmFkZS5tYXQ0JFYyX2xhYmVsLCBsZXZlbHMgPSAgYygiRyIsICJHMStHMiIsICJJIGxvZzEwIiwgIkkiLCAiSStJZyBsb2cxMCIsICJJK0lnIiwgIkkxK0kyIGxvZzEwIiwgIkkxK0kyIiwgIklnIGxvZzEwIiwgIklnIiwgIklnMStJZzIiLCAiUiBsb2cxMCIsICJSIiwgInN1bSBsb2cxMCIsICJzdW0iLCAiRyBsb2cxMCIpKQpgYGAKCgojIHBsb3QgaW52YXNpb24gbWF0cml4CmBgYHtyfQppbnZhc2lvbi5wbDEgPC0gZ2dwbG90KGRhdGEgPSBpbnZhZGUubWF0NCwgYWVzKHggPSBWMl9sYWJlbCwgeSA9IFYxX2xhYmVsLCBmaWxsID0gaW52YXNpb25fMikpICsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siKSArCiAgdGhlbWVfbWluaW1hbCgpICsgIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAxLCBoanVzdCA9IDEpLAogIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgcGxvdC5tYXJnaW49bWFyZ2luKHIgPSAwKSkgKyAKICBsYWJzKGZpbGwgPSAiSW52YXNpYmlsaXR5IiwgeCA9ICJDb21wZXRpbmcgY3VlIiwgeSA9ICJSZWZlcmVuY2UgY3VlIikgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gcmV2KSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJDb21wZXRpdGl2ZSBleGNsdXNpb25cbm9mIGFub3RoZXIgY3VlIiA9ICIjNDU3NWI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbmJ5IGFub3RoZXIgY3VlIiA9ICIjZmM4ZDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNdXR1YWwgaW52YXNpb24iID0gIiNmZWUwOTAiKSwKICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJ3aGl0ZSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyBjcmVhdGUgc3VtbWFyeSBiYXIgY2hhcnQKYGBge3J9CiMgY3JlYXRlIGEgc3RhY2tlZCBiYXJjaGFydCBmb3Igc3VtbWFyeQojIyBmaWx0ZXIgb3V0IG5hCmludmFkZS5tYXRhbHQgPC0gaW52YWRlLm1hdDMgJT4lIG5hLmV4Y2x1ZGUoKQoKIyBnZXQgZnJxdWVuY3kgZnJvbSBib3RoIHNpZGVzLiBOb3RlIHdoZW4gZ3JvdXBpbmcgZm9yIFYyLCBmcm9tIHRoZSBwZXJzcGVjdGl2ZSBvZiBjdWUgMiwgc2NlbmFycmlvIHdoZW4gc3RyYWluIDIgaW52YWRlID0gc3RyYWluIDEgaW52YWRlCmludmFkZS5tYXRhbHQxIDwtIGludmFkZS5tYXRhbHQgJT4lIGdyb3VwX2J5KFYxX2xhYmVsLCBpbnZhc2lvbikgJT4lIAogIHN1bW1hcml6ZShmcmVxdWVuY3lfMSA9IG4oKSkKCmludmFkZS5tYXRhbHQyIDwtIGludmFkZS5tYXRhbHQgJT4lCiAgbXV0YXRlKGludmFzaW9uX2FsdCA9IGNhc2Vfd2hlbigKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiB+ICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiB+ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJNdXR1YWwgaW52YXNpb24iIH4gIk11dHVhbCBpbnZhc2lvbiIsCiAgICBpbnZhc2lvbiA9PSAiTXV0dWFsIG5vbi1pbnZhc2lvbiIgfiAiTXV0dWFsIG5vbi1pbnZhc2lvbiIKICApKSAlPiUgCiAgZ3JvdXBfYnkoVjJfbGFiZWwsIGludmFzaW9uX2FsdCkgJT4lIAogIHN1bW1hcml6ZShmcmVxdWVuY3lfMiA9IG4oKSkgICAgIAoKIyBmdWxsIGpvaW4gYW5kIHN1bS4gaGFzIGNvbmZpcm1lZCBhbGwgb2YgdGhlbSBhZGQgdXAgdG8gMTQgCmludmFkZS5tYXRhbHQzIDwtIGZ1bGxfam9pbihpbnZhZGUubWF0YWx0MSwgaW52YWRlLm1hdGFsdDIsIGJ5ID0gYygiVjFfbGFiZWwiID0gIlYyX2xhYmVsIiwgImludmFzaW9uIiA9ICJpbnZhc2lvbl9hbHQiKSkKCmludmFkZS5tYXRhbHQzW2lzLm5hKGludmFkZS5tYXRhbHQzKV0gPC0gMAppbnZhZGUubWF0YWx0NCA8LSBpbnZhZGUubWF0YWx0MyAlPiUgCiAgbXV0YXRlKGZyZXEgPSBmcmVxdWVuY3lfMSArIGZyZXF1ZW5jeV8yKSAlPiUgCiAgbXV0YXRlKHRlbXAgPSBjYXNlX3doZW4oCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIgfiBmcmVxCiAgKSkgJT4lIAogIGdyb3VwX2J5KFYxX2xhYmVsKSAlPiUgCiAgbXV0YXRlKGludmFkZV8xX2ZyZXEgPSBtYXgodGVtcCwgbmEucm0gPSBUKSkgJT4lIAogIG11dGF0ZShpbnZhc2lvbl8yID0gY2FzZV93aGVuKAogICAgaW52YXNpb24gPT0gIk11dHVhbCBpbnZhc2lvbiIgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiB+ICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbm9mIGFub3RoZXIgY3VlIiwKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiB+ICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbmJ5IGFub3RoZXIgY3VlIgogICkpCmBgYAoKCgpgYGB7cn0KaW52YXNpb24ucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhID0gaW52YWRlLm1hdGFsdDQsIGFlcyh4ID0gZnJlcSwgeSA9IHJlb3JkZXIoVjFfbGFiZWwsIGludmFkZV8xX2ZyZXEpLCBmaWxsID0gZm9yY2F0czo6ZmN0X3JldihmYWN0b3IoaW52YXNpb25fMiwgbGV2ZWxzID0gYygiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5vZiBhbm90aGVyIGN1ZSIsICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbmJ5IGFub3RoZXIgY3VlIiwgIk11dHVhbCBpbnZhc2lvbiIsICJNdXR1YWwgbm9uLWludmFzaW9uIikpKSksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh4ID0gIkZyZXF1ZW5jeSIsIGZpbGwgPSAiSW52YXNpYmlsaXR5IiwgeSA9ICJDdWUiKSArCiAgdGhlbWVfYncoKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiID0gIiM0NTc1YjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiID0gIiNmYzhkNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk11dHVhbCBpbnZhc2lvbiIgPSAiI2ZlZTA5MCIpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKQpgYGAKCiMgcGxvdCB0b2dldGhlcgpgYGB7cn0KZ2dhcnJhbmdlKGludmFzaW9uLnBsMSwgaW52YXNpb24ucGwyLCBhbGlnbiA9ICJoIiwgY29tbW9uLmxlZ2VuZCA9IFQsIHdpZHRocyA9IGMoMiwgMSkpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2ludmFzaW9uX2EudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTEwMCwgc2NhbGUgPSAxLjQsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKIy0tLS0tLS0tLS0tLS0tLS0gaW52YXNpb24gcGFpcndpc2UgY29tcGFyaXNvbi0tLS0tLS0tLS0tLS0tLS0tIwojIyBwcm9jZXMgZGF0YQpgYGB7cn0KIyBqb2luIGludmFkZSBkZiB3aXRoIGxhYmVsIGJlY2F1c2UgSSBhbSBsYXp5CmludmFkZS5kZjIgPC0gaW52YWRlLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2lfMSA9IGxhYmVsX2NpKSwgYnkgPSBjKCJtdXRfaWQiID0gImlkX2NpIikpCgppbnZhZGUuZGYyIApgYGAKCiMgbG9nCmBgYHtyfQojIGdldCBub24tbG9nZ2VkIHBhaXJpbmdzCmludmFkZV9ub2xvZyA8LSBpbnZhZGUuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSB0cmltd3MoZ3N1YigiXFwgLioiLCAiIiwgbGFiZWxfY2lfMSkpLAogICAgICAgICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSkgJT4lIAogIGZpbHRlcihsb2dfMSA9PSAibm9uZSIpCgoKaW52YWRlX2xvZyA8LSBpbnZhZGUuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSB0cmltd3MoZ3N1YigiXFwgLioiLCAiIiwgbGFiZWxfY2lfMSkpLAogICAgICAgICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSkgJT4lIAogIGZpbHRlcihsb2dfMSA9PSAibG9nIikKCmludmFkZV9sb2cuZGYgPC0gbGVmdF9qb2luKAogIHNlbGVjdChpbnZhZGVfbm9sb2csIGN1ZV8xLCByZXNfaWQsIGxvZ18xLCBOb25lID0gZml0bmVzcyksCiAgc2VsZWN0KGludmFkZV9sb2csIGN1ZV8xLCByZXNfaWQsIGxvZ18xLCBMb2cgPSBmaXRuZXNzKSwKICBieSA9IGMoImN1ZV8xIiwgInJlc19pZCIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShOb25lKSAmICFpcy5uYShMb2cpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKExvZyA+IE5vbmUsICJMb2dnZWQgYmV0dGVyIiwgIk5vdCBsb2dnZWQgYmV0dGVyIikpCgppbnZhZGVfbG9nCmBgYAoKIyBjb21iaW5lZApgYGB7cn0KaW52YWRlX25vY29tYiA8LSBpbnZhZGUuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJub25lIikKCmludmFkZV9jb21iIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gImNvbWIiKQogIAppbnZhZGVfY29tYi5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KGludmFkZV9ub2NvbWIsIGN1ZV8xLCByZXNfaWQsIGxvZ18xLCBTZWxmID0gZml0bmVzcyksCiAgc2VsZWN0KGludmFkZV9jb21iLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgVG90YWwgPSBmaXRuZXNzKSwKICBieSA9IGMoImN1ZV8xIiwgImxvZ18xIiwgInJlc19pZCIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShUb3RhbCkgJiAhaXMubmEoU2VsZikpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoVG90YWwgPiBTZWxmLCAiVG90YWwgYmV0dGVyIiwgIlNlbGYgYmV0dGVyIikpCmludmFkZV9jb21iLmRmCmBgYAoKIyBwbG90CmBgYHtyfQppbnZhZGVfbG9nLnBsIDwtIGdncGFpcmVkKGludmFkZV9sb2cuZGYsIGNvbmQxID0gIk5vbmUiLCBjb25kMiA9ICJMb2ciLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHggPSAiQ3VlIHBlcmNlcHRpb24iLCB5ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSIsIGNvbG9yID0gIkVmZmVjdCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTm90IGxvZ2dlZCBiZXR0ZXIiID0gIiNmYzhkNTkiLCAiTG9nZ2VkIGJldHRlciIgPSAiIzQ1NzViNCIpKSsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAtMCkKCmludmFkZV9jb21iLnBsIDwtIGdncGFpcmVkKGludmFkZV9jb21iLmRmLCBjb25kMSA9ICJUb3RhbCIsIGNvbmQyID0gIlNlbGYiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHggPSAiQ3VlIHBlcmNlcHRpb24iLCB5ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSIsIGNvbG9yID0gIkVmZmVjdCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVG90YWwgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIlNlbGYgYmV0dGVyIiA9ICIjNDU3NWI0IikpKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wKQoKZ2dhcnJhbmdlKGludmFkZV9sb2cucGwsIGludmFkZV9jb21iLnBsLCBhbGlnbiA9ICJoIiwgbmNvbCA9IDIpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2ludmFzaW9uX2IudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gOTAwLCBzY2FsZSA9IDEuMiwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgQ3VlIHBlcmZvcm1hbmNlIGFjcm9zcyBzaW5nbGUsIGNvLWluZmVjdGlvbiwgc3RhdGljLCBhbmQgaW52YXNpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCmBgYHtyfQojIGltcG9ydCBpbiBhbGwgdGhlIHJhbmtzCnNpX29wdC5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL3NpX29wdC5jc3YiKSkKY2lfb3B0LmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfb3B0LmNzdiIpKQpzdGF0aWMuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCmludmFzaW9uLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfaW52YXNpb24uY3N2IikpCgojIGNhbGN1bGF0ZSBtZWFuIGZpdG5lc3MKc3RhdGljLm1lYW4gIyMgYWxyZWFkeSBjYWxjdWxhdGVkCmludmFzaW9uLm1lYW4gPC0gcmJpbmQoc2VsZWN0KGludmFzaW9uLmRmLCBjdWUgPSBtdXRfaWQsIGZpdG5lc3MpLAogICAgICBzZWxlY3QoaW52YXNpb24uZGYgJT4lIG11dGF0ZShmaXRuZXNzMiA9IGZpdG5lc3MgKiAtMSksIGN1ZSA9IHJlc19pZCwgZml0bmVzcyA9IGZpdG5lc3MyKSkgJT4lIAogIGdyb3VwX2J5KGN1ZSkgJT4lIAogIHN1bW1hcml6ZShtZWFuX2ZpdG5lc3MgPSBtZWFuKGZpdG5lc3MpKSAlPiUgCiAgYXJyYW5nZShkZXNjKG1lYW5fZml0bmVzcykpCgojIGNhbGN1bGF0ZSByYW5rcwpzaS5yYW5rIDwtIHNpX29wdC5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGlkX3NpLCBsYWJlbCA9IGV6X2xhYmVsX3NpKSwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkgJT4lIAogIG11dGF0ZShyYW5rID0gZGVuc2VfcmFuaygtZml0bmVzc18yMCksCiAgICAgICAgIG1vZGVsID0gIlNpbmdsZSBpbmZlY3Rpb24iKSAlPiUgCiAgc2VsZWN0KHJhbmssIG1vZGVsLCBpZCA9IGlkX2NpLCBsYWJlbCkKCmNpLnJhbmsgPC0gY2lfb3B0LmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGNpX2ZpdG5lc3MuZGYsIHZhbHVlLCBsYWJlbCksIGJ5ID0gImxhYmVsIikgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBpZF9zaSwgZXpfbGFiZWwpLCBieSA9IGMoImlkIiA9ICJpZF9jaSIpKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSByYW5rKC12YWx1ZSksCiAgICAgICAgIG1vZGVsID0gIkNvLWluZmVjdGlvbiIpICU+JSAKICBzZWxlY3QocmFuaywgbW9kZWwsIGlkLCBsYWJlbCA9IGV6X2xhYmVsKQoKc3RhdGljLnJhbmsgPC0gc3RhdGljLm1lYW4gJT4lIAogIG11dGF0ZShsYWJlbF9jaSA9IGdzdWIoImxvZzEwIiwgImxvZyIsIGxhYmVsX2NpXzEpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGxhYmVsX2NpLCBlel9sYWJlbCksIGJ5ID0gYygibGFiZWxfY2kiID0gImxhYmVsX2NpIikpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoLW1lYW5fZml0bmVzcyksCiAgICAgICAgIG1vZGVsID0gIlN0YXRpYyBtaXhlZCBnZW5vdHlwZSIpICU+JSAKICBzZWxlY3QocmFuaywgbW9kZWwsIGlkID0gaWRfY2ksIGxhYmVsID0gZXpfbGFiZWwpCgppbnZhc2lvbi5yYW5rIDwtIGludmFzaW9uLm1lYW4gJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBlel9sYWJlbCksIGJ5ID0gYygiY3VlIiA9ICJpZF9jaSIpKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSByYW5rKC1tZWFuX2ZpdG5lc3MpLAogICAgICAgICBtb2RlbCA9ICJJbnZhc2l2ZSBtaXhlZCBnZW5vdHlwZSIpICU+JSAKICBzZWxlY3QocmFuaywgbW9kZWwsIGlkID0gY3VlLCBsYWJlbCA9IGV6X2xhYmVsKSAlPiUgCiAgbXV0YXRlKGxhYmVsID0gZ3N1YigiXG4iLCAiICIsIHBhc3RlMCgiICAgIiwgbGFiZWwpKSkKCnN0YXRpYy5yYW5rCiMgY29uY2F0ZW5hdGUKZml0bmVzcy5yYW5rIDwtIHJiaW5kKAogIHNpLnJhbmssIGNpLnJhbmssIHN0YXRpYy5yYW5rLCBpbnZhc2lvbi5yYW5rCikgJT4lIAogIG11dGF0ZShtb2RlbCA9IGZjdF9yZWxldmVsKG1vZGVsLCBjKCJTaW5nbGUgaW5mZWN0aW9uIiwgIkNvLWluZmVjdGlvbiIsICJTdGF0aWMgbWl4ZWQgZ2Vub3R5cGUiLCAiSW52YXNpdmUgbWl4ZWQgZ2Vub3R5cGUiKSkpCgojIGhpZ2hsaWdodCB0aGUgZ29vZCBvbmVzCmZpdG5lc3MucmFua19nb29kIDwtIGZpdG5lc3MucmFuayAlPiUgCiAgZmlsdGVyKGlkICVpbiUgYygiSWctaV9sb2ciLCAiSS1pK0lnLWlfbG9nIiwgInN1bV9sb2ciLCAiRy1pX2xvZyIpKQpgYGAKCiMgcGxvdApgYGB7cn0KbGlicmFyeShnZ2J1bXApCgpnZ3Bsb3QoKSArCiAgZ2VvbV9idW1wKGRhdGEgPSBmaXRuZXNzLnJhbmssIGFlcyh4ID0gbW9kZWwsIHkgPSByYW5rLCBncm91cCA9IGlkKSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRuZXNzLnJhbmssIGFlcyh4ID0gbW9kZWwsIHkgPSByYW5rLCBncm91cCA9IGlkKSwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAzKSArCiAgZ2VvbV9idW1wKGRhdGEgPSBmaXRuZXNzLnJhbmtfZ29vZCwgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQsIGNvbG9yID0gaWQpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZml0bmVzcy5yYW5rX2dvb2QsIGFlcyh4ID0gbW9kZWwsIHkgPSByYW5rLCBncm91cCA9IGlkLCBjb2xvciA9IGlkKSwgc2l6ZSA9IDMpICsKICBnZW9tX3RleHQoZGF0YSA9IGludmFzaW9uLnJhbmssIGFlcyh4ID0gbW9kZWwsIHkgPSByYW5rLCBsYWJlbCA9IGxhYmVsKSwgc2l6ZSA9IDMuNSwgaGp1c3QgPSAwLCBpbmhlcml0LmFlcyA9IEYpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIGV4cGFuZF9saW1pdHMoeCA9IDUuNSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnMoeCA9ICJNb2RlbCIsIHkgPSAiTWVhbiBmaXRuZXNzIHJhbmsiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9maXRuZXNzX3JhbmsudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTUwMCwgc2NhbGUgPSAxLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCgojLT09PT09PT09PT09PT09PT09PT09PSMKIyBQYXJ0aXRpb25pbmcgYmVzdCBjdWUKIz09PT09PT09PT09PT09PT09PT09PS0jCiMtLS0tLS0tIHNpbmdsZSBpbmZlY3Rpb24gLS0tLS0tLS0tLS0jCiMgcmVkbyBzb21lIG9wdGltaXphdGlvbiAobG93ZXIgZml0bmVzcyBpbiBubyBSIHRoYW4gZGVmYXVsdCkKYGBge3J9CnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW5fUi5SIikpCnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW5fTi5SIikpCiMgSSBub25lCmNsIDwtIG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkpOyBzZXREZWZhdWx0Q2x1c3RlcihjbCA9IGNsKQpJX25vX1IgPC0gb3B0aW1QYXJhbGxlbCgKICAgIHBhciA9IHJlcCgwLjUsNCksICMgc3RhcnQgYXQgMC41eDQKICAgIGZuID0gY2hhYmF1ZGlfc2lfY2xlYW5fUiwgCiAgICBjb250cm9sID0gbGlzdCh0cmFjZSA9IDYsIGZuc2NhbGUgPSAtMSksCiAgICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICAgIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgICBjdWVfcmFuZ2UgPSAgc2VxKDAsIDYqKDEwXjYpLCBieSA9ICg2KigxMF42KSkvNTAwMCksCiAgICBjdWUgPSAiSSIsCiAgICBsb2dfY3VlID0gIm5vbmUiLAogICAgc29sdmVyID0gInZvZGUiKQpzdG9wQ2x1c3RlcihjbCkKIyAwLjE0NDAyMSAtNDMuMTA0NiAyMDMwLjI3IC01MjQuNjg2IAojIDguNjk1ODkKYGBgCgojIGltcG9ydCBhbmQgcHJvY2VzcyBkYXRhCmBgYHtyfQojIGltcG9ydCBpbiBkYXRhCnNpX3BhcnRpdGlvbi5scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaS8iKSwgcGF0dGVybiA9ICIqLmNzdiIsIGZ1bGwubmFtZXMgPSBUKQpzaV9wYXJ0aXRpb24ubHMgPC0gbGFwcGx5KHNpX3BhcnRpdGlvbi5scywgcmVhZC5jc3YpCnNpX3BhcnRpdGlvbi5kZiA8LSBkby5jYWxsKHJiaW5kLCBzaV9wYXJ0aXRpb24ubHMpCgojIGNvbWJpbmUgd2l0aCBzaSBmaXRuZXNzIChkZWZhdWx0KQpzaV9wYXJ0aXRpb24uZGYgPC0gc2lfcGFydGl0aW9uLmRmICU+JSBsZWZ0X2pvaW4oc2VsZWN0KHNpX2ZpdG5lc3MuZGYsIGlkLCBmaXRuZXNzID0gdmFsdWUpLCBieSA9ICJpZCIpCgojIG1ha2UgbG9uZ2VyCnNpX3BhcnRpdGlvbi5kZjIgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihzaV9wYXJ0aXRpb24uZGYsIGMoZml0bmVzc19SLCBmaXRuZXNzX04sIGZpdG5lc3NfVywgZml0bmVzcykpCgojIGNhbGN1bGF0ZSBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24uIEFsc28gcmVuYW1lCnNpX3BhcnRpdGlvbi5kZjIgPC0gc2lfcGFydGl0aW9uLmRmMiAlPiUgCiAgZ3JvdXBfYnkobmFtZSkgJT4lIAogIG11dGF0ZShjdiA9IHNkKHZhbHVlKS9tZWFuKHZhbHVlKSoxMDAsCiAgICAgICAgIG1lYW4gPSBtZWFuKHZhbHVlKSwKICAgICAgICAgY2F0ZWdvcnkgPSBjYXNlX3doZW4oCiAgICAgICAgICAgbmFtZSA9PSAiZml0bmVzc19SIiB+ICJObyBSQkMgbGltaXRhdGlvbiIsCiAgICAgICAgICAgbmFtZSA9PSAiZml0bmVzc19XIiB+ICJObyB0YXJnZXRlZCBpbW11bml0eSIsCiAgICAgICAgICAgbmFtZSA9PSAiZml0bmVzc19OIiB+ICJObyBpbmRpc2NyaW1pbmF0ZVxuaW1tdW5pdHkiLAogICAgICAgICAgIG5hbWUgPT0gImZpdG5lc3MiIH4gIkRlZmF1bHQiCiAgICAgICAgICkpCgpgYGAKCiMgcGxvdApgYGB7cn0KbGlicmFyeSh1bmdldml6KQojIHJhdyBmaXRuZXNzCnNpX3BhcnRpdGlvbi5wbDEgPC0gZ2dwbG90KCkgKwogIGdlb21fdnBsaW5lKGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IG1lYW4sIGdyb3VwID0gY2F0ZWdvcnksIGNvbG9yID0gY2F0ZWdvcnkpLCBzaG93LmxlZ2VuZCA9IEYsIHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChkYXRhID0gc2lfcGFydGl0aW9uLmRmMiwgYWVzKHkgPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgbWVhbiksIHggPSB2YWx1ZSksIHNpemUgPSAyLCBhbHBoYSA9IDAuNykgKwogIGdlb21fbGluZShkYXRhID0gc2lfcGFydGl0aW9uLmRmMiwgYWVzKHkgPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgbWVhbiksIHggPSB2YWx1ZSwgZ3JvdXAgPSBpZCksIGFscGhhID0gMC4yKSArCiAgbGFicyh4ID0gIkZpdG5lc3MiLCB5ID0gIkNvbmRpdGlvbnMiKSArCiAgdGhlbWVfYncoKQoKIyBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24Kc2lfcGFydGl0aW9uLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoZGF0YSA9IHNpX3BhcnRpdGlvbi5kZjIsIGFlcyh5ID0gZmN0X3Jlb3JkZXIoY2F0ZWdvcnksIG1lYW4pLCB4ID0gY3YpLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnMoeCA9ICJDb2VmZmljaWVudCBvZlxudmFyaWF0aW9uICglKSIsIHkgPSAiIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpCgpzaV9wYXJ0aXRpb24ucGwgPC0gZ2dhcnJhbmdlKHNpX3BhcnRpdGlvbi5wbDEsIHNpX3BhcnRpdGlvbi5wbDIsIHdpZHRocyA9IGMoMSwgMC4zKSwgYWxpZ24gPSAiaCIpCnNpX3BhcnRpdGlvbi5wbAoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uX2ZpdG5lc3MudGlmZiIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQpCmBgYAoKIy0tLS0tLS0gY29uc2VxdWVuY2VzIG9mIG5vIHRhcmdldGVkIGltbXVuaXR5IC0tLS0tLS0tLS0tLSMKIyBnZXQgZHluYW1pY3Mgb2Ygbm8gdGFyZ2V0ZWQgaW1tdW5pdHkKYGBge3J9CmdldF9keW4gPC0gZnVuY3Rpb24oZGYpewogIAogIHNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW5fVy5SIikpCiAgaWQgPC0gZGYkaWQKICBjdWUgPC0gZGYkY3VlCiAgbG9nIDwtIGRmJGxvZwogIHBhciA8LSBjKGRmJHZhcl9XMSwgZGYkdmFyX1cyLCBkZiR2YXJfVzMsIGRmJHZhcl9XNCkKICBjdWVfcmFuZ2UgPC0gc2VxKGRmJGxvdywgZGYkaGlnaCwgYnkgPSBkZiRieSkKICAKICAjIGdldCBkeW5hbWljcwogIGR5biA8LSBjaGFiYXVkaV9zaV9jbGVhbl9XKAogICAgcGFyYW1ldGVyc19jciA9IHBhciwKICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICAgIGN1ZV9yYW5nZSA9ICBjdWVfcmFuZ2UsCiAgICBjdWUgPSBjdWUsCiAgICBsb2dfY3VlID0gbG9nLAogICAgc29sdmVyID0gInZvZGUiLAogICAgZHluID0gVAogICkKICAKICAjIGNvbWJpbmUKICBkeW4yIDwtIGNiaW5kKGR5biwgaWQgPSBpZCwgY3VlID0gY3VlLCBsb2cgPSBsb2cpCiAgCiAgd3JpdGVfcGFycXVldChkeW4yLCBwYXN0ZTAoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZHluLyIpLCBpZCwgIl9ub1dfZHluLnBhcnF1ZXQiKSkKICAKfQpgYGAKCiMgZ2V0IGRmIHRvIHJ1bgpgYGB7cn0KIyBqb2luIHdpdGggY3VlX3JhbmdlCmN1ZV9yYW5nZV9zaS5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2N1ZV9yYW5nZV9zaS5jc3YiKSkKc2lfcGFydGl0aW9uLmRmMyA8LSBzaV9wYXJ0aXRpb24uZGYgJT4lIGxlZnRfam9pbihzZWxlY3QoY3VlX3JhbmdlX3NpLmRmLCBsb3csIGhpZ2gsIGJ5LCBpZCksICJpZCIpCgojIGxhcHBseSBsb29wCnNpX3BhcnRpdGlvbi5scyA8LSBzcGxpdChzaV9wYXJ0aXRpb24uZGYzLCBzZXEobnJvdyhzaV9wYXJ0aXRpb24uZGYzKSkpCm1jbGFwcGx5KHNpX3BhcnRpdGlvbi5scywgZ2V0X2R5bikKYGBgCgojIHByb2Nlc3MgZGF0YWZyYW1lCmBgYHtyfQojIGltcG9ydCBpbiBkYXRhZnJhbWUKbm9fVy5scyA8LSBsaXN0LmZpbGVzKGhlcmUoImRhdGEvcGFydGl0aW9uL3NpX2R5bi8iKSwgcGF0dGVybiA9ICIqbm9XX2R5bi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCm5vX1cuZGYgPC0gbGFwcGx5KG5vX1cubHMsIHJlYWRfcGFycXVldCkKbm9fVy5kZiA8LSBkby5jYWxsKHJiaW5kLCBub19XLmRmKQoKIyBjb21iaW5lIHdpdGggZXogbGFiZWwKZXpfbGFiZWwgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9lel9sYWJlbC5jc3YiKSkKbm9fVy5kZiA8LSBsZWZ0X2pvaW4obm9fVy5kZiwgZXpfbGFiZWwsIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCgojIGdldCBjb252ZXJzaW9uIHJhdGUgCm5vX1cuY3IgPC0gbm9fVy5kZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpCm5vX1cuSSA8LSBub19XLmRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIkkiKQoKIyBnZXQgZGVmYXVsdCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKc2lfZHluLmRmIDwtIGxlZnRfam9pbihzaV9keW4uZGYsIGV6X2xhYmVsLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQpzaV9keW4uY3IgPC0gc2lfZHluLmRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikKc2lfZHluLkkgPC0gc2lfZHluLmRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIkkiKQpgYGAKCiMgcGxvdCBjb252ZXJzaW9uIHJhdGUKbWVjaGFuaXNtOiB0YXJnZXRlZCBpbW11bml0eSBsZWQgdG8gbG93ZXIgcGFyYXNpdGUgZGVuc2l0eSBpbiB0aGUgaW5pdGlhbCBzdGFnZXMsIHdoaWNoIHByZXZlbnRzIHBhcmFzaXRlcyBmcm9tIG1ha2luZyB0aGUgc3dpdGNoIGZyb20gbm8gY29udmVyc2lvbiByYXRlIHRvIGhpZ2ggY29udmVyc2lvbiByYXRlLiBXaGVuIHBhcnNpdGUgZGVuc2l0eSB1bmRlcmdvZXMgZHJhc3RpYyBpbmNyZWFzZSBhdCB0aGUgYmVnaW5uaW5nIGR1ZSB0byBsb3dlciBpbW11bml0eSwgdGhpcyBwcmVzZW50cyBhIGhpZ2hlciBkZWdyZWUgb2Ygc2lnbmFsIHRoYXQgYWxsb3dzIHBhcmFzaXRlIHRvIG1ha2UgdGhlIHN3aXRjaCBhcHByb3ByaWF0ZWx5CmBgYHtyfQpwYXJ0aXRpb25fY3IucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gbm9fVy5jciwgYWVzKHggPSB0aW1lLCB5PSB2YWx1ZSwgY29sb3IgPSAiTm8gdGFyZ2V0ZWQgaW1tdW5pdHkiKSkgKwogIGdlb21fbGluZShkYXRhID0gc2lfZHluLmNyLCBhZXMoeCA9IHRpbWUsIHk9IHZhbHVlLCBjb2xvciA9ICJEZWZhdWx0IikpICsKICBmYWNldF93cmFwKH5lel9sYWJlbF9zaSwgbmNvbCA9IDUpICsKICB4bGltKDAsIDIwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNykgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIiwgY29sb3IgPSAiQ29uZGl0aW9uIikgKwogIHRoZW1lX2J3KCkKCm5vX1cuY3IKYGBgCgojLS0tLS0gY3VlIHN0YXRlIC0tLS0tLS0tLS0tLS0tIwoKIyBmdW5jdGlvbiB0byBnZXQgY3VlIHN0YXRlcwpgYGB7cn0KIyBmdW5jdGlvbiB0byBnZXQgY3VlIHN0YXRlcwpnZXRfY3VlX3N0YXRlIDwtIGZ1bmN0aW9uKGRmKXsKICBjdWUgPC0gdHJpbXdzKGdzdWIoIl9sb2d8X25vbmUiLCAiIiwgdW5pcXVlKGRmJGlkKSkpCiAgaWYoY3VlICE9ICJJK0lnIil7CiAgZGYyIDwtIGRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gY3VlKQogIGlmKHN0cl9kZXRlY3QodW5pcXVlKGRmJGlkKSwgImxvZyIpKXsKICAgIGRmMiA8LSBkZjIgJT4lIAogICAgICBtdXRhdGUodmFsdWUgPSBsb2cxMCh2YWx1ZSkpCiAgfQogIH0KICAKICBpZihjdWUgPT0gIkkrSWciKXsKICAgIGRmMiA8LSBkZiAlPiUgZmlsdGVyKHZhcmlhYmxlICVpbiUgYygiSSIsICJJZyIpKSAlPiUgCiAgICAgIGdyb3VwX2J5KHRpbWUpICU+JSAKICAgICAgbXV0YXRlKHZhbHVlID0gc3VtKHZhbHVlKSkKICAgIAogICAgaWYoc3RyX2RldGVjdCh1bmlxdWUoZGYkaWQpLCAibG9nIikpewogICAgZGYyIDwtIGRmMiAlPiUgCiAgICAgIG11dGF0ZSh2YWx1ZSA9IGxvZzEwKHZhbHVlKSkKICB9CiAgfQogIAogIGRmMiR2YWx1ZVtkZjIkdmFsdWUgPT0gLUluZl0gPC0gMAogIAogIHdyaXRlX3BhcnF1ZXQoZGYyLCBwYXN0ZTAoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZGVmYXVsdF9zdGF0ZS8iKSwgdW5pcXVlKGRmJGlkKSwgIl9ub1dfc3RhdGUucGFycXVldCIpKQp9CmBgYAoKIyBydW4gZnVuY3Rpb24KYGBge3J9CiMgc3BsaXQgZHluYW1pY3MgYmFzZWQgb24gaWQKbm9fVy5zcGxpdCA8LSBzcGxpdChub19XLmRmLCBub19XLmRmJGlkKQoKIyBydW4gZnVuY3Rpb24KbWNsYXBwbHkobm9fVy5zcGxpdCwgZ2V0X2N1ZV9zdGF0ZSkKCiMgZ2V0IGRhdGFmcmFtZQpub19XLnN0YXRlIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfc3RhdGUvIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCm5vX1cuc3RhdGUgPC0gbGFwcGx5KG5vX1cuc3RhdGUsIHJlYWRfcGFycXVldCkKbm9fVy5zdGF0ZSA8LSBkby5jYWxsKHJiaW5kLCBub19XLnN0YXRlKQpub19XLnN0YXRlJHZhbHVlW25vX1cuc3RhdGUkdmFsdWUgPCAwXSA8LSAwCgojIGdldCBzYW1lIGZvciBzaSBpbmZlY3Rpb24KZGVmYXVsdC5zcGxpdCA8LSBzcGxpdChzaV9keW4uZGYsIHNpX2R5bi5kZiRpZCkKbWNsYXBwbHkoZGVmYXVsdC5zcGxpdCwgZ2V0X2N1ZV9zdGF0ZSkKZGVmYXVsdC5zdGF0ZSA8LSBsaXN0LmZpbGVzKGhlcmUoImRhdGEvcGFydGl0aW9uL3NpX2RlZmF1bHRfc3RhdGUvIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCmRlZmF1bHQuc3RhdGUgPC0gbGFwcGx5KGRlZmF1bHQuc3RhdGUsIHJlYWRfcGFycXVldCkKZGVmYXVsdC5zdGF0ZSA8LSBkby5jYWxsKHJiaW5kLCBkZWZhdWx0LnN0YXRlKQpkZWZhdWx0LnN0YXRlJHZhbHVlW2RlZmF1bHQuc3RhdGUkdmFsdWUgPCAwXSA8LSAwCgojIG1hbnVhbGx5IGNvcnJlY3Qgbm9uLWxvZ2dpbmcKSV9JZy5jb3JyIDwtIG5vX1cuc3RhdGUgJT4lIGZpbHRlcihpZCA9PSAiSStJZ19sb2ciKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gbG9nMTAodmFsdWUpKQpJX0lnLmNvcnIkdmFsdWVbSV9JZy5jb3JyJHZhbHVlIDwgMF0gPC0gMAoKbm9fVy5zdGF0ZTIgPC0gbm9fVy5zdGF0ZSAlPiUgZmlsdGVyKGlkICE9ICJJK0lnX2xvZyIpCm5vX1cuc3RhdGUyIDwtIG5vX1cuc3RhdGUyICU+JSByYmluZChub19XLnN0YXRlMiwgSV9JZy5jb3JyKQpgYGAKCiMgcGxvdAphYnNlbmNlIG9mIHRhcmdldGVkIGltbXVuaXR5IGxlZCB0byBkcmFzdGljIGluY3JlYXNlIGluIHBhcmFzaXRlIGRlbnNpdHkgaW4gZWFybHkgcGhhc2VzIG9mIGluZmVjdGlvbi4gVGhpcyBwcm9kdWNlcyBoaWdoIHNpZ25hbCBpbnRlbnNpdHkgZm9yIHBhcmFzaXRlIGFuZCBob3N0LWJhc2VkIGN1ZXMsIGVzcGVjaWFsbHkgbm9uLWxvZ2dlZCBvbmVzLCB3aGljaCBhbGxvd3MgZm9yIHN0YXRlIGRpZmZlcmVudGF0aW9uLiBXaGlsZSB0aGlzIGNhbiBiZSB2aWV3ZWQgYXMgYSBtb2RlbGxpbmcgYXJ0aWZpYWN0LCBpdCBzaG91bGQgYmUgbm90ZWQgdGhhdCB0aGUgbG9nZ2VkIGN1ZXMgc2VsZG9tIGNoYW5nZWQgYXMgdGhlc2UgY2hhbmdlcyBpbiBlYXJseSBpbmZlY3Rpb24gZGlkIGxpdHRsZSB0byBhbHRlciB0aGUgYWN0dWFsIGVhcmx5IHNpZ25hbCBpbnRlbnNpdHkgc2Vuc2VkIGJ5IHRoZSBwYXJhc2l0ZS4gSW4gYW4gZW52aXJvbm1lbnQgd2hlcmUgdGhlcmUgaXMgaGV0ZXJvZ2VuZWl0eSBpbiBob3N0IHJlc3BvbnNlLCBhbmQgdGh1cywgc2lnbmFsLCBsb2dnaW5nIGFsbG93cyBmb3IgcGFyYXNpdGVzIHRvIGFkYXB0IG9wdGltYWwgc3RyYXRlZ3kgd2hlcmVhcyBub24tbG9nZ2VkIGN1ZXMgbXVzdCBjb250ZW5kIHdpdGggc2Vuc2l0aXZpdHkgdG8gaW1tdW5pdHkuCmBgYHtyfQojIGZ1bmN0aW9uIHRvIGluZGl2aWR1YWxseSBwbG90IHN0dWZmCnBsb3Rfc3RhdGUgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogICMgcGxvdCBzdGF0ZSBkeW5hbWljcwogIHN0YXRlX3BsIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGRmMSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUsIGNvbG9yID0gbmFtZSwgZ3JvdXAgPSBuYW1lKSkgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsX3NpLCBzY2FsZXMgPSAiZnJlZSIpICsKICB4bGltKDEsMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgbGFicyh4ID0gIiIsIHkgPSAiQ3VlIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9YygiRGVmYXVsdCIgPSAiIzQ1NzViNCIsICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiID0gIiNmYzhkNTkiKSkKICAKICAjIHBsb3QgY29udmVyc2lvbiByYXRlIGR5bmFtaWNzCiAgY3JfcGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcmFzdGVyKGRhdGEgPSBkZjIsIGFlcyh4ID0gdGltZSwgeSA9IG5hbWUsIGZpbGwgPSB2YWx1ZSkpICsKICB4bGltKDEsMjApICsKICB0aGVtZV9idygpICsKICAgIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhsaW0gPSBjKDAsIDEpKQogIAogICMgYXJyYW5nZQogIGdnYXJyYW5nZShzdGF0ZV9wbCwgY3JfcGwsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIsIGhlaWdodHMgPSBjKDEsIDAuNCkpCiAgZ2dzYXZlKHBhc3RlMChoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3BhcnRpdGlvbi8iKSwgdW5pcXVlKGRmMSRpZCksICIudGlmZiIpLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMy41KQp9CmBgYAoKIyBzcGxpdApgYGB7cn0KIyBjb21iaW5lIHN0YXRlCm5vV19kZWZhdWx0LnN0YXRlIDwtIGxlZnRfam9pbigKICBzZWxlY3Qobm9fVy5zdGF0ZTIsIHRpbWUsIGBObyB0YXJnZXRlZFxuaW1tdW5pdHlgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIAogIHNlbGVjdChkZWZhdWx0LnN0YXRlICU+JSBmaWx0ZXIodGltZSA8PSAyMCksIHRpbWUsIGBEZWZhdWx0YCA9IHZhbHVlLCBpZCwgZXpfbGFiZWxfc2kpLCBieSA9IGMoInRpbWUiLCAiaWQiLCAiZXpfbGFiZWxfc2kiKSkKCm5vV19kZWZhdWx0LnN0YXRlMiA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKG5vV19kZWZhdWx0LnN0YXRlLCBjKGBObyB0YXJnZXRlZFxuaW1tdW5pdHlgLCBgRGVmYXVsdGApKQojIGNvbWJpbmUgY29udmVyc2lvbiByYXN0ZXIKbm9XX2RlZmF1bHQuY3IgPC0gbGVmdF9qb2luKAogIHNlbGVjdChub19XLmNyLCB0aW1lLCBgTm8gdGFyZ2V0ZWRcbmltbXVuaXR5YCA9IHZhbHVlLCBpZCwgZXpfbGFiZWxfc2kpLCAKICBzZWxlY3Qoc2lfZHluLmNyICU+JSBmaWx0ZXIodGltZSA8PSAyMCksIHRpbWUsIGBEZWZhdWx0YCA9IHZhbHVlLCBpZCwgZXpfbGFiZWxfc2kpLCBieSA9IGMoInRpbWUiLCAiaWQiLCAiZXpfbGFiZWxfc2kiKSkKbm9XX2RlZmF1bHQuY3IyIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIobm9XX2RlZmF1bHQuY3IsIGMoYE5vIHRhcmdldGVkXG5pbW11bml0eWAsIGBEZWZhdWx0YCkpCgojIHNwbGl0Cm5vV19kZWZhdWx0X3N0YXRlLmxzIDwtIHNwbGl0KG5vV19kZWZhdWx0LnN0YXRlMiwgbm9XX2RlZmF1bHQuc3RhdGUyJGlkKQpub1dfZGVmYXVsdF9jci5scyA8LSBzcGxpdChub1dfZGVmYXVsdC5jcjIsIG5vV19kZWZhdWx0LmNyMiRpZCkKCiMgcnVuIGZ1bmN0aW9uCm1hcHBseShwbG90X3N0YXRlLCBub1dfZGVmYXVsdF9zdGF0ZS5scywgbm9XX2RlZmF1bHRfY3IubHMpCmBgYAoKIy0tLS0tLS0tIHJlYWN0aW9uIG5vcm1zIG9mIGRlZmF1bHQgdnMgb3B0aW1pemVkIC0tLS0tLS0tLS0tLSMKIyBnZXQgcmVhY3Rpb24gbm9ybSBhbmQgcnVnIGRhdGEKYGBge3J9CnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvcGFyX3RvX2RmLlIiKSkKCiMgR2FtZXRvY3l0ZQpnX2xvZy5ybiA8LSBwYXJfdG9fZGYocGFyID0gYygxLjIxMTUyMSwJLTMuOTM2Nzc4LAktMS4zMTI5NDQsCS0xLjI4NTcxMyksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF40KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjQpKSkvNTAwMCkpCmdfbG9nLnJuMiA8LSBwYXJfdG9fZGYocGFyID0gYygxLjM5Mzg2MDUzOSwJLTQuMjUzMDA3NjE2LAktMC4zMTM5NDcwMjksCS0yLjAwMDg1NzM0NCksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF40KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjQpKSkvNTAwMCkpCgpnLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDAuMDQwNjEyODgsCS05LjMxNDQ1OTU4LAk3NC4xMzAxNTUwNiwJLTQzMS41OTg0MzY0KSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjQpLCBieSA9ICg2KigxMF40KSkvNTAwMCkpCmcucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDAuNTQxNzI5MDczLAktMy45MDQ2MTY0NDMsCTAuODc0ODc0MTIsCS0wLjY5NDE3NzAyMSksIGN1ZV9yYW5nZSA9IHNlcSgwLCA2KigxMF40KSwgYnkgPSAoNiooMTBeNCkpLzUwMDApKQoKIyBJK0lnCklfSWdfbG9nLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDMuNTk0MDQyLAk0LjE1Nzc0NCwJLTEzLjUzMDY3MiwJMi41OTk5MDUpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgbG9nMTAoNiooMTBeNikpLCBieSA9IChsb2cxMCg2KigxMF42KSkpLzUwMDApKQpJX0lnX2xvZy5ybjIgPC0gcGFyX3RvX2RmKHBhciA9IGMoNjMuNzE4OTM4MjIsCS04Ny43NzY3MTYwMSwJLTU2LjU1NDc1NTE0LAktNjYuMDIyMDk1NDkpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgbG9nMTAoNiooMTBeNikpLCBieSA9IChsb2cxMCg2KigxMF42KSkpLzUwMDApKQoKSV9JZy5ybiA8LSBwYXJfdG9fZGYocGFyID0gYygwLjMxNTkyOTcsCS00Ni4xMTA0NTU4LAkxMjUwLjc1MjkwOCwJLTYuMTk4MjA5MyksIGN1ZV9yYW5nZSA9IHNlcSgwLCA2KigxMF42KSwgYnkgPSAoNiooMTBeNikpLzUwMDApKQpJX0lnLnJuMiA8LSBwYXJfdG9fZGYocGFyID0gYygwLjczMTk4Mjc4NCwJLTIxLjY5Nzk5NDQ5LAkxNDkuNzg0MTg3NiwJMTcuMDI1NTE3NjkpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgNiooMTBeNiksIGJ5ID0gKDYqKDEwXjYpKS81MDAwKSkKCiMgY29udmVydCBsb2cgdG8gbm9uLWxvZ2dlZCBzY2FsZQpnX2xvZy5ybiRjdWVfcmFuZ2UgPC0gMTBeKGdfbG9nLnJuJGN1ZV9yYW5nZSkKZ19sb2cucm4yJGN1ZV9yYW5nZSA8LSAxMF4oZ19sb2cucm4yJGN1ZV9yYW5nZSkKSV9JZ19sb2cucm4kY3VlX3JhbmdlIDwtIDEwXihJX0lnX2xvZy5ybiRjdWVfcmFuZ2UpCklfSWdfbG9nLnJuMiRjdWVfcmFuZ2UgPC0gMTBeKElfSWdfbG9nLnJuMiRjdWVfcmFuZ2UpCgojIGdldCBydWcKZ19sb2cucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiRyBsb2ciKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gMTBedmFsdWUpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKZ19sb2cucnVnMiA8LSBub19XLnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkcgbG9nIikgJT4lIAogIG11dGF0ZSh2YWx1ZSA9IDEwXnZhbHVlKSAlPiUgCiAgZmlsdGVyKHZhbHVlIDw9IDYqKDEwXjQpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWdfbG9nLnJ1ZyA8LSBkZWZhdWx0LnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkkrSWcgbG9nIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpJX0lnX2xvZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyBsb2ciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCmcucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiRyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiRyIgJiB2YWx1ZSA8PSA2KigxMF40KSkgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpJX0lnLnJ1ZyA8LSBkZWZhdWx0LnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkkrSWciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWcucnVnMiA8LSBub19XLnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkkrSWciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCiMgZ2V0IHJ1ZyBsaW1pdHMKcnVnX2xpbSA8LSByYmluZChnX2xvZy5ydWcsCiAgICAgICAgICAgICAgICAgZ19sb2cucnVnMiwKICAgICAgICAgICAgICAgICBJX0lnX2xvZy5ydWcsCiAgICAgICAgICAgICAgICAgSV9JZ19sb2cucnVnMiwKICAgICAgICAgICAgICAgICBnLnJ1ZywKICAgICAgICAgICAgICAgICBnLnJ1ZzIsCiAgICAgICAgICAgICAgICAgSV9JZy5ydWcsCiAgICAgICAgICAgICAgICAgSV9JZy5ydWcyKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfc2kpICU+JSAKICBzdW1tYXJpemUobWF4ID0gbWF4KGhhYmxhcjo6cyh2YWx1ZSksIG5hLnJtID0gVCksCiAgICAgICAgICAgIG1pbiA9IG1pbihoYWJsYXI6OnModmFsdWUpLCBuYS5ybSA9IFQpKQoKIyBjb21iaW5lIGFuZCBmaWx0ZXIKcm4gPC0gcmJpbmQoCiAgY2JpbmQoZ19sb2cucm4sIGxhYmVsX3NpID0gIkcgbG9nIiwgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICBjYmluZChnX2xvZy5ybjIsIGxhYmVsX3NpID0gIkcgbG9nIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogIGNiaW5kKGcucm4sIGxhYmVsX3NpID0gIkciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKGcucm4yLCBsYWJlbF9zaSA9ICJHIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogIGNiaW5kKElfSWdfbG9nLnJuLCBsYWJlbF9zaSA9ICJJK0lnIGxvZyIsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgY2JpbmQoSV9JZ19sb2cucm4yLCBsYWJlbF9zaSA9ICJJK0lnIGxvZyIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICBjYmluZChJX0lnLnJuLCBsYWJlbF9zaSA9ICJJK0lnIiwgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICBjYmluZChJX0lnLnJuMiwgbGFiZWxfc2kgPSAiSStJZyIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKQopICU+JSAKICBsZWZ0X2pvaW4ocnVnX2xpbSwgYnkgPSAibGFiZWxfc2kiKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfc2kpICU+JSAKICBmaWx0ZXIoY3VlX3JhbmdlIDw9IG1heCAmIGN1ZV9yYW5nZSA+PSBtaW4pCgojIGNvbWJpbmUgcnVnCnJ1ZyA8LSByYmluZChjYmluZChnX2xvZy5ydWcsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgICAgICAgICAgICBjYmluZChnX2xvZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChnLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKGcucnVnMiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogICAgICAgICAgICAgY2JpbmQoSV9JZ19sb2cucnVnLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogICAgICAgICAgICAgY2JpbmQoSV9JZ19sb2cucnVnMiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogICAgICAgICAgICAgY2JpbmQoSV9JZy5ydWcsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgICAgICAgICAgICBjYmluZChJX0lnLnJ1ZzIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSkKCiMgY29iaW5lIHdpdGggZXpsYWJlbApybjIgPC0gcm4gJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSAibGFiZWxfc2kiKQpydWcyIDwtIHJ1ZyAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCgojIGZpbHRlciBydWcKZGVmYXVsdC5ydWcgPC0gcnVnMiAlPiUgZmlsdGVyKGNvbmRpdGlvbiA9PSAiRGVmYXVsdCIpCm5vLnJ1ZyA8LSBydWcyICU+JSBmaWx0ZXIoY29uZGl0aW9uID09ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKQpgYGAKCiMgcGxvdApgYGB7cn0KZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gcm4yLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9IGNvbmRpdGlvbikpICsKICBnZW9tX3J1ZyhkYXRhID0gZGVmYXVsdC5ydWcsIGFlcyh4ID0gdmFsdWUsIGNvbG9yID0gY29uZGl0aW9uKSwgc2lkZXMgPSAiYiIpICsKICBnZW9tX3J1ZyhkYXRhID0gbm8ucnVnLCBhZXMoeCA9IHZhbHVlLCBjb2xvciA9IGNvbmRpdGlvbiksIHNpZGVzID0gInQiKSArCiAgZmFjZXRfd3JhcCh+ZmN0X3JlbGV2ZWwoZXpfbGFiZWxfc2ksIGMoIkdhbWV0b2N5dGUgbG9nMTAiLCAiR2FtZXRvY3l0ZSIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsICJBc2V4dWFsJnNleHVhbCBpUkJDIikpLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9YygiRGVmYXVsdCIgPSAiIzQ1NzViNCIsICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiID0gIiNmYzhkNTkiKSkgKwogIHlsaW0oMCwgMS4xKSArCiAgbGFicyh4ID0gIkN1ZSByYW5nZSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIiwgY29sb3IgPSAiQ29uZGl0aW9uIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3BhcnRpdGlvbl9ybi50aWZmIiksIHdpZHRoID0gNy41LCBoZWlnaHQgPSA2KQpgYGAKCiMgZ2V0IGNvbnZlcnNpb24gcmF0ZSBsZWdlbmQKYGBge3J9Cm5vV19kZWZhdWx0LmNyICU+JSBmaWx0ZXIoaWQgPT0gIkdfbG9nIikgJT4lIApnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoYWVzKHggPSB0aW1lLCB5ID0gaWQsIGZpbGwgPSBEZWZhdWx0KSkgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogICAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwKICAgICAgICAgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLCkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltID0gYygwLCAxKSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2NyX2xlZ2VuZC50aWZmIikpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIERpc2Vhc2UgY3VydmVzIGZvciBzaW5nbGUsIGNvLWluZmVjdGlvbiwgYW5kIGludmFzaW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGdldCBkYXRhIGZvciBkaXNlYXNlIGN1cnZlcwpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uIGR5bmFtaWNzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCgojIGNvLWluZmVjdGlvbiBkeW5hbWljcyAobW9uLWN1ZSkKY2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9keW4ucGFycXVldCIpKQoKIyBkdWFsIGN1ZSBkeW5hbWljcwpkdWFsX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kdWFsX2N1ZV9keW4vZHVhbF9jdWVfZHluLnBhcnF1ZXQiKSkKYGBgCgojLS0tLS0tLSBzaW5nbGUgY3VlIGNvbXBhcmlzb24gLS0tLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBnZXQgY2xhc3NpZmljYXRpb24Kc2lfY3VlLmR2IDwtIHNpX2ZpdG5lc3MuZGYgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGNhc2Vfd2hlbigKICAgIHZhbHVlID4gOS4yIH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSA5LjIgfiAiUG9vci1wZXJmb3JtaW5nIgogICkpCgojIHByb2Nlc3MgZHluYW1pY3MgLT4gdHVybiBza2lubnkKc2lfZGMuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gIkkiIHwgdmFyaWFibGUgPT0gIklnIiB8IHZhcmlhYmxlID09ICJSIikgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUpICU+JSAKICBtdXRhdGUodG90YWwgPSBJK0lnKQoKIyBqb2luIHdpdGggY2xhc3NpZmljYWl0b24Kc2lfZGMuZGYyIDwtIHNpX2RjLmRmICU+JSBsZWZ0X2pvaW4oc2VsZWN0KHNpX2N1ZS5kdiwgaWQsIGNsYXNzaWZpY2F0aW9uKSwgYnkgPSAiaWQiKQpzaV9jdWUuZHYKIyBzcGxpdCBpbnRvIHRvcCBlcmZvcm1pbmcgYW5kIHBvb3ItcGVyZm9ybWluZyBjdWVzCnNpX2RjLmhpZ2ggPC0gc2lfZGMuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIkhpZ2gtcGVyZm9ybWluZyIpCnNpX2RjLnBvb3IgPC0gc2lfZGMuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIlBvb3ItcGVyZm9ybWluZyIpCgojIGpvaW4gaGlnaCBwZXJmb3JtaW5nIHdpdGggbGFiZWwKc2lfZGMuaGlnaCA8LSBzaV9kYy5oaWdoICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwgJT4lIGRpc3RpbmN0KGxhYmVsX3NpLCAua2VlcF9hbGwgPSBUKSwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCiN3cml0ZV9wYXJxdWV0KHNpX2RjLmhpZ2gsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zaV9kY19oaWdoLnBhcnF1ZXQiKSkKI3dyaXRlX3BhcnF1ZXQoc2lfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX3Bvb3IucGFycXVldCIpKQpgYGAKCiMgcGxvdApgYGB7cn0Kc2lfZGMucG9vciA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX3Bvb3IucGFycXVldCIpKQpzaV9kYy5oaWdoIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfaGlnaC5wYXJxdWV0IikpCgojIHBsb3QKc2lfZGMucHJlIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IHNpX2RjLnBvb3IsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gaWQpLCBjb2xvciA9ICJkYXJrIGdyZXkiLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIlNpbmdsZSBpbmZlY3Rpb25cbmdvb2QgcGVyZm9ybWluZyBjdWVzIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiKSArCiAgdGhlbWVfYncoKSsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSwgYWNjdXJhY3kgPSAwLjEpKSArCiAgZ3VpZGVzKHNoYXBlID0gRkFMU0UpCgpzaV9kYy5wbCA8LSBzaV9kYy5wcmUgKwogIGdlb21fcG9pbnQoZGF0YSA9IHNpX2RjLmhpZ2ggJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PTApLCBhZXMoeCA9IHRvdGFsLCB5ID0gUiwgY29sb3IgPSBlel9sYWJlbCwgc2hhcGUgPSBlel9sYWJlbCksIHNpemUgPSAzKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBzaV9kYy5oaWdoLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGV6X2xhYmVsLCBjb2xvciA9IGV6X2xhYmVsKSwgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIsICIjZmRjYjQ0IiwgIiM5MWJmZGIiKSkgICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUpKQpgYGAKCiMtLS0tLS0tLS0tIGNvLWluZmVjdGlvbiBtb25vY3VlIC0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGdldCByZWxldmVudCB2YXJpYWJsZXMKY2lfZGMuZGYgPC0gY2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gIkkxIiB8IHZhcmlhYmxlID09ICJJZzEiIHwgdmFyaWFibGUgPT0gIlIiKQoKIyBtb3JwaCBpbnRvIHNraW5ueSBmb3JtYXQKY2lfZGMuZGYgPC0gdGlkeXI6OnBpdm90X3dpZGVyKGNpX2RjLmRmLCBuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUsIGlkX2NvbHMgPSBjKHRpbWUsIGxhYmVsKSkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IEkxK0lnMSkKCiMgZ29vZCBjdWUgYmFkIGN1ZQpjaV9jdWUuZHYgPC0gY2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiAyLjI1IH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSAyLjI1IH4gIlBvb3ItcGVyZm9ybWluZyIKICApKQoKIyBqb2luIHdpdGggY2xhc3NpZmljYWl0b24KY2lfZGMuZGYyIDwtIGNpX2RjLmRmICU+JSBsZWZ0X2pvaW4oY2lfY3VlLmR2LCBieSA9ICJsYWJlbCIpCgojIHNwbGl0IGludG8gdG9wIGVyZm9ybWluZyBhbmQgcG9vci1wZXJmb3JtaW5nIGN1ZXMKY2lfZGMuaGlnaCA8LSBjaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiSGlnaC1wZXJmb3JtaW5nIikKY2lfZGMucG9vciA8LSBjaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiUG9vci1wZXJmb3JtaW5nIikKCiMgam9pbiBoaWdoIHBlcmZvcm1pbmcgd2l0aCBsYWJlbApjaV9kYy5oaWdoMiA8LSBjaV9kYy5oaWdoICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCgojd3JpdGVfcGFycXVldChjaV9kYy5oaWdoMiwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX2hpZ2gucGFycXVldCIpKQojd3JpdGVfcGFycXVldChjaV9kYy5wb29yLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfcG9vci5wYXJxdWV0IikpCmBgYAoKIyBwbG90CmBgYHtyfQpjaV9kYy5wb29yIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfcG9vci5wYXJxdWV0IikpCmNpX2RjLmhpZ2gyIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfaGlnaC5wYXJxdWV0IikpCgojIHBsb3QKY2lfZGMucHJlIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IGNpX2RjLnBvb3IsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gbGFiZWwpLCBjb2xvciA9ICJkYXJrIGdyZXkiLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIkNvLWluZmVjdGlvblxuZ29vZCBwZXJmb3JtaW5nIGN1ZXMiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIpICsKICB0aGVtZV9idygpKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpICsKICBndWlkZXMoc2hhcGUgPSBGQUxTRSkKCmNpX2RjLnBsIDwtIGNpX2RjLnByZSArCiAgZ2VvbV9wb2ludChkYXRhID0gY2lfZGMuaGlnaDIgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PTApLCBhZXMoeCA9IHRvdGFsLCB5ID0gUiwgY29sb3IgPSBlel9sYWJlbCwgc2hhcGUgPSBlel9sYWJlbCksIHNpemUgPSAzKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBjaV9kYy5oaWdoMiwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBlel9sYWJlbCwgY29sb3IgPSBlel9sYWJlbCksIHNpemUgPSAxLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoICIjNDU3NWI0IiwgIiNmYzhkNTkiLCAiI2ZkY2I0NCIsICIjOTFiZmRiIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUpKQoKYGBgCgojLS0tLS0tLS0tIGR1YWwgY3VlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyB0dXJuIHNraW5ueQpkdWFsX2RjLmRmIDwtIGR1YWxfZHluLmRmICU+JSAKICBtdXRhdGUobGFiZWxfYWx0ID0gcGFzdGUobGFiZWwsICIrIiAsIGxhYmVsX2IpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX2FsdCwgdGltZSwgdmFyaWFibGUsIHZhbHVlKSAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJJIiB8IHZhcmlhYmxlID09ICJJZyIgfCB2YXJpYWJsZSA9PSAiUiIpICU+JSAKICBkaXN0aW5jdChsYWJlbF9hbHQsIHRpbWUsIHZhcmlhYmxlLCAua2VlcF9hbGwgPSBUKQoKZHVhbF9keW4uZGYKCmR1YWxfZGMuZGYyIDwtIGR1YWxfZGMuZGYgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUsIGlkX2NvbHMgPSBjKHRpbWUsIGxhYmVsX2FsdCkpICU+JQogIG11dGF0ZSh0b3RhbCA9IEkrSWcpCgp3cml0ZV9wYXJxdWV0KGR1YWxfZGMuZGYyLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kYy5wYXJxdWV0IikpCgojIGdvb2QgZHVhbCBjdWUgLT4gbGlzdCBvZiBnb29kIHBlcmZvcm1pbmcgZHVhbCBjdWVzIHRoYXQgZW5jb21wYXNzIHdpZGUgdmFyaWV0eSBvZiBjdWVzCnNlbGVjdGVkX2R1YWxfY3VlIDwtIGMoIlIgbG9nICsgSSBsb2ciLCAiUiArIElnIGxvZyIsICJHIGxvZyArIEkgbG9nIiwgIkcgbG9nICsgSWcgbG9nIiwgIklnICsgSSBsb2ciKQpiYWRfZHVhbF9jdWUgPC0gYygiRyArIEkiLCAiUiArIElnIiwgIlIgbG9nICsgSWciLCAiRyArIFIiLCAiRyArIFIgbG9nIiwgIkcgKyBJZyIsICJJZyArIEkiLCAiUiArIEkiLCAiUiBsb2cgKyBJIikKCiMgZ2V0IGNsYXNzaWZpY2F0aW9uIC0+IFIgbG9nMTAgKyBJIGxvZzEwIGFzIHRoZSBvbmx5IGdvb2Qgb25lCmR1YWxfZGMuaGlnaCA8LSBkdWFsX2RjLmRmMiAlPiUgZmlsdGVyKGxhYmVsX2FsdCAlaW4lIHNlbGVjdGVkX2R1YWxfY3VlKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2FsdCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2FsdCkpCmR1YWxfZGMucG9vciA8LSBkdWFsX2RjLmRmMiAlPiUgZmlsdGVyKGxhYmVsX2FsdCAlaW4lIGJhZF9kdWFsX2N1ZSkgJT4lIAogIG11dGF0ZShsYWJlbF9hbHQgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbF9hbHQpKQojd3JpdGVfcGFycXVldChkdWFsX2RjLmhpZ2gsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjX2hpZ2gucGFycXVldCIpKQojd3JpdGVfcGFycXVldChkdWFsX2RjLnBvb3IsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjX3Bvb3IucGFycXVldCIpKQoKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfZGMuaGlnaCA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfaGlnaC5wYXJxdWV0IikpCmR1YWxfZGMucG9vciA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfcG9vci5wYXJxdWV0IikpCgpkdWFsX2RjLmhpZ2gyIDwtIGR1YWxfZGMuaGlnaCAlPiUgCiAgZmlsdGVyKGxhYmVsX2FsdCA9PSAiUiBsb2cxMCArIEkgbG9nMTAiKQoKIyBhZGQgCmR1YWxfZGMucHJlIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfZGMucG9vciwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBsYWJlbF9hbHQpLCBjb2xvciA9ICJkYXJrIGdyZXkiLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIkhpZ2gtcGVyZm9ybWluZ1xuZHVhbCBjdWVzIHBlciDCtUwiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyIsIHkgPSAiUkJDIHBlciDCtUwiKSArCiAgdGhlbWVfYncoKSsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSwgYWNjdXJhY3kgPSAwLjEpKSArCiAgZ3VpZGVzKHNoYXBlID0gRkFMU0UpCgoKZHVhbF9kYy5wbCA8LSBkdWFsX2RjLnByZSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9kYy5oaWdoMiAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09MCksIGFlcyh4ID0gdG90YWwsIHkgPSBSLCBzaGFwZSA9IGxhYmVsX2FsdCksIGNvbG9yID0gIiM0NTc1YjQiLCBzaXplID0gMykgKwogIGdlb21fcGF0aChkYXRhID0gZHVhbF9kYy5oaWdoMiwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBsYWJlbF9hbHQpLCBjb2xvciA9ICIjNDU3NWI0Iiwgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAwLjEpKSkKYGBgCgojLS0tLS0tLS0tIGNvLWluZmVjdGlvbiBzdGF0aWMgLS0tLS0tLS0tLS0tLS0tLSMKYGBge3J9CiMgaW1wb3J0IGluIGR5bmFtaWNzIGRhdGEKc3RhdGljX2R5bi5scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL2NpX3N0YXRpYy8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKc3RhdGljX2R5bi5scyA8LSBsYXBwbHkoc3RhdGljX2R5bi5scywgcmVhZF9wYXJxdWV0KQoKIyBmaWx0ZXIgdmFyaWFibGUgYW5kIHRyYW5zZm9ybQpzdGF0aWNfZHluLmxzMiA8LSBtY2xhcHBseShzdGF0aWNfZHluLmxzLCBmdW5jdGlvbih4KXsKICB4ICU+JSAKICAgIGZpbHRlcih2YXJpYWJsZSA9PSAiSTEiIHwgdmFyaWFibGUgPT0gIklnMSIgfCB2YXJpYWJsZSA9PSAiSTIiIHwgdmFyaWFibGUgPT0gIklnMiIgfCB2YXJpYWJsZSA9PSAiUiIpICU+JSAKICAgIG11dGF0ZShpZF9hbHQgPSBwYXN0ZShpZF8xLCBpZF8yKSkgJT4lIAogICAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgaWRfY29scyA9IGModGltZSwgaWRfYWx0KSkgJT4lCiAgbXV0YXRlKHRvdGFsMSA9IEkxK0lnMSwgdG90YWwyID0gSTIrSWcyKQp9KQoKc3RhdGljX2RjLmRmIDwtIGRvLmNhbGwocmJpbmQsIHN0YXRpY19keW4ubHMyKQpzdGF0aWNfZGMuZGYgPC0gc3RhdGljX2RjLmRmICU+JSAKICBtdXRhdGUoaWRfMSA9IGdzdWIoIiAuKiIsICIiLCBpZF9hbHQpLAogICAgICAgICBpZF8yID0gZ3N1YigiLiogIiwgIiIsIGlkX2FsdCkpICU+JSAKICBmaWx0ZXIoaWRfMSAhPSBpZF8yKQojd3JpdGVfcGFycXVldChzdGF0aWNfZGMuZGYsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zdGF0aWNfZGMucGFycXVldCIpKQpgYGAKCiMgZnVydGhlciBwcm9jZXNzaW5nCmBgYHtyfQpzdGF0aWNfZGMuZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zdGF0aWNfZGMucGFycXVldCIpKQojIGdldCB3aW5uZXJzIGFuZCBsb3NlcnMKIyMgaW1wb3J0IGluIGZpdG5lc3MKc3RhdGljX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCiMjIGdldCB3aW5uZXIgc2l0dWF0aW9uCnN0YXRpY19maXRuZXNzLmRmMiA8LSBzdGF0aWNfZml0bmVzcy5kZiAlPiUgCiAgZmlsdGVyKGlkXzEgIT0gaWRfMikgJT4lIAogIG11dGF0ZSh3aW5uaW5nX2lkID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IGlkXzEsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiBpZF8yCiAgKSwKICBsb3NpbmdfaWQgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPCAwIH4gaWRfMSwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZT4gMCB+IGlkXzIKICApKQoKIyBsZWZ0IGpvaW4Kc3RhdGljX2RjLmRmMiA8LSBzdGF0aWNfZGMuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc3RhdGljX2ZpdG5lc3MuZGYyLCBpZF8xLCBpZF8yLCB3aW5uaW5nX2lkLCBsb3NpbmdfaWQsIGZpdG5lc3NfZGlmZmVyZW5jZSksIGJ5ID0gYygiaWRfMSIsICJpZF8yIikpCgojIGdldCB3aW5uZXItbG9zZXIgZGlmZmVyZW5jZSBpbiB0ZXJtcyBvZiBJK0lnIGFsc28gZmlsdGVyIG91dCB0byBvbnlsIHZlcnkgc3Ryb25nIGZpdG5lc3MgZGlmZmVyZW5jZQpzdGF0aWNfZGMuZGYzIDwtIHN0YXRpY19kYy5kZjIgJT4lIAogIG11dGF0ZSh0b3RhbF9kaWZmID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IHRvdGFsMS10b3RhbDIsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDItdG90YWwyCiAgKSwKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwxLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwyCiAgKSwKICB0b3RhbF9sb3NlciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDEKICApKSAlPiUgCiAgZmlsdGVyKGFicyhmaXRuZXNzX2RpZmZlcmVuY2UpID4gMC41KQpgYGAKCiMgcGxvdApgYGB7cn0Kc3RhdGljX2RjLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IHN0YXRpY19kYy5kZjMsIGFlcyh4PSB0b3RhbF93aW5uZXIsIHkgPSBSLCBncm91cCA9IGlkX2FsdCwgY29sb3IgPSAiV2lubmVyIiksIGFscGhhID0gMC41LCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBnZW9tX3BhdGgoZGF0YSA9IHN0YXRpY19kYy5kZjMsIGFlcyh4PSB0b3RhbF9sb3NlciwgeSA9IFIsIGdyb3VwID0gaWRfYWx0LCBjb2xvciA9ICJMb3NlciIpLAogICAgICAgICAgYWxwaGEgPSAwLjUsYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJTdGF0dXMiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyIsIHkgPSAiUkJDIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiV2lubmVyIiA9ICIjNDU3NWI0IiwiTG9zZXIiPSAiI2ZjOGQ1OSIpKSAgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpCmBgYAoKCiMtLS0tLS0tLS1jby1pbmZlY3Rpb24gaW52YXNpb24gLS0tLS0tLS0tLS0tLS0tIwojIGdldCBpbnZhc2lvbiBkeW5hbWljCmBgYHtyfQojIGdldCBpbnZhc2lvbiBkZgppbnZhc2lvbl9maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfaW52YXNpb24uY3N2IikpCgojIGdldCBjdWUgcmFuZ2UKY2lfY3VlX3JhbmdlIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY3VlX3JhbmdlX2NpLmNzdiIpKQppbnZhc2lvbl9maXRuZXNzLmRmMiA8LSBpbnZhc2lvbl9maXRuZXNzLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGNpX2N1ZV9yYW5nZSwgaWQsIG11dF9jdWUgPSBjdWUsIG11dF9sb3cgPSBsb3csIG11dF9oaWdoID0gaGlnaCwgbXV0X2J5ID0gYnkpLCBieSA9IGMoIm11dF9pZCI9ICJpZCIpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChjaV9jdWVfcmFuZ2UsIGlkLCByZXNfY3VlID0gY3VlLCByZXNfbG93ID0gbG93LCByZXNfaGlnaCA9IGhpZ2gsIHJlc19ieSA9IGJ5KSwgYnkgPSBjKCJyZXNfaWQiPSAiaWQiKSkKYGBgCgojIGZ1bmN0aW9uIHRvIGdldCBkeW5hbWljCmBgYHtyfQpnZXRfaW52YXNpb25fZHluIDwtIGZ1bmN0aW9uKGRmKXsKICAjIGdldCBjdWVzCiAgbXV0X2N1ZSA8LSBkZiRtdXRfY3VlCiAgcmVzX2N1ZSA8LSBkZiRyZXNfY3VlCiAgCiAgIyBnZXQgaW5mbyBvZiBjdWVzIChmb3IgY28gaW5mZWN0aW9uKQogIGlmKHN0cmluZ3I6OnN0cl9kZXRlY3QobXV0X2N1ZSwgIi1pIikpe211dF9jdWUgPSBnc3ViKCIqLWkiLCAiMSIsIG11dF9jdWUpfQogIGlmKHN0cmluZ3I6OnN0cl9kZXRlY3QobXV0X2N1ZSwgIi1pIiwgbmVnYXRlID0gVCkpe211dF9jdWUgPSBtdXRfY3VlfQogIGlmKHN0cmluZ3I6OnN0cl9kZXRlY3QocmVzX2N1ZSwgIi1pIikpe3Jlc19jdWUgPSBnc3ViKCIqLWkiLCAiMiIsIHJlc19jdWUpfQogIGlmKHN0cmluZ3I6OnN0cl9kZXRlY3QocmVzX2N1ZSwgIi1pIiwgbmVnYXRlID0gVCkpe3Jlc19jdWUgPSByZXNfY3VlfQogIAogICMgZ2V0IGxvZwogIG11dF9sb2cgPC0gaWZlbHNlKHN0cmluZ3I6OnN0cl9kZXRlY3QoZGYkbXV0X2lkLCAibG9nIiksICJsb2cxMCIsICJub25lIikKICByZXNfbG9nIDwtIGlmZWxzZShzdHJpbmdyOjpzdHJfZGV0ZWN0KGRmJHJlc19pZCwgImxvZyIpLCAibG9nMTAiLCAibm9uZSIpCiAgCiAgIyBnZXQgcGFyYW1ldGVycwogIG11dF9wYXIgPC0gYyhkZiRtdXRfdmFyMV9vcHQsIGRmJG11dF92YXIyX29wdCwgZGYkbXV0X3ZhcjNfb3B0LCBkZiRtdXRfdmFyNF9vcHQpCiAgcmVzX3BhciA8LSBjKGRmJHJlc192YXIxLCBkZiRyZXNfdmFyMiwgZGYkcmVzX3ZhcjMsIGRmJHJlc192YXI0KQogIAogICMgZ2V0IGN1ZSByYW5nZQogIG11dF9jdWVfcmFuZ2UgPC0gc2VxKGRmJG11dF9sb3csIGRmJG11dF9oaWdoLCBieSA9IGRmJG11dF9ieSkKICByZXNfY3VlX3JhbmdlIDwtIHNlcShkZiRyZXNfbG93LCBkZiRyZXNfaGlnaCwgYnkgPSBkZiRyZXNfYnkpCiAgCiAgIyBnZXQgZHluYW1pY3Mgb2YgY28gaW5mZWN0aW9uCiAgY2lfZHluIDwtIGNoYWJhdWRpX2NpX2NsZWFuKAogICAgcGFyYW1ldGVyc19jcl8xID0gbXV0X3BhciwKICAgIHBhcmFtZXRlcnNfY3JfMiA9IHJlc19wYXIsCiAgICAgICAgICAgICAgICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgICAgICAgICAgICAgICAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgICAgICAgICAgICAgICAgIGN1ZV8xID0gbXV0X2N1ZSwKICAgICAgICAgICAgICAgICAgY3VlXzIgPSByZXNfY3VlLAogICAgICAgICAgICAgICAgICBjdWVfcmFuZ2VfMSA9IG11dF9jdWVfcmFuZ2UsCiAgICAgICAgICAgICAgICAgY3VlX3JhbmdlXzIgPSByZXNfY3VlX3JhbmdlLAogICAgICAgICAgICAgICAgbG9nX2N1ZV8xID0gbXV0X2xvZywKICAgICAgICAgICAgICAgIGxvZ19jdWVfMiA9IHJlc19sb2csCiAgICAgICAgICAgICAgICBzb2x2ZXIgPSAidm9kZSIsCiAgICAgICAgICAgICAgICB0aW1lX3JhbmdlID0gc2VxKDAsIDMwLCAwLjAwMSksCiAgICBkeW4gPSBUKQogIAogICMgYXBwZW5kIGxhYmVsIHRvIGFsbCBkZgogY2lfZHluMiA8LSBjYmluZChjaV9keW4sIG11dF9pZCA9IGRmJG11dF9pZCwgcmVzX2lkID0gZGYkcmVzX2lkKQogIAogICMgd3JpdGUKIHdyaXRlX3BhcnF1ZXQoY2lfZHluMiwgcGFzdGUwKGhlcmUoImRhdGEvY2lfaW52YXNpb25fZHluLyIpLCBkZiRtdXRfaWQsICItIiwgZGYkcmVzX2lkLCAiLnBhcnF1ZXQiKSkKfQpgYGAKCgojIHJ1biBkeW5hbWljIGZ1bmNpdG9uCmBgYHtyfQojIGdldCBmdW5jdGlvbiBhbmQgcGFyYW1ldGVycwpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX2NpX2NsZWFuLlIiKSkKcGFyYW1ldGVyc190c3VrdXNoaSA8LSBjKFIxID0gOC44OSooMTBeNiksICMgc2xpZ2h0bHkgaGlnaGVyCiAgICAgICAgICAgICAgICBsYW1iZGEgPSAzLjcqKDEwXjUpLAogICAgICAgICAgICAgICAgbXUgPSAwLjAyNSwgCiAgICAgICAgICAgICAgICBwID0gOCooMTBeLTYpLCAjIGRvdWJsZWQgZm9ybSBvcmlnaW5hbAogICAgICAgICAgICAgICAgYWxwaGEgPSAxLCAKICAgICAgICAgICAgICAgIGFscGhhZyA9IDIsIAogICAgICAgICAgICAgICAgYmV0YSA9IDUuNzIxLCAKICAgICAgICAgICAgICAgIG11bSA9IDQ4LCAKICAgICAgICAgICAgICAgIG11ZyA9IDQsIAogICAgICAgICAgICAgICAgSTAgPSA0My44NTk2NSwgCiAgICAgICAgICAgICAgICBJZzAgPSAwLCAKICAgICAgICAgICAgICAgIGEgPSAxNTAsIAogICAgICAgICAgICAgICAgYiA9IDEwMCwgCiAgICAgICAgICAgICAgICBzcCA9IDEsCiAgICAgICAgICAgICAgICBwc2luID0gMTYuNjkyMzQsCiAgICAgICAgICAgICAgICBwc2l3ID0gMC44NDMxNzg1LAogICAgICAgICAgICAgICAgcGhpbiA9IDAuMDM1MjA1OTEsIAogICAgICAgICAgICAgICAgcGhpdyA9IDU1MC44NDIsCiAgICAgICAgICAgICAgICBpb3RhID0gMi4xOCooMTBeNiksCiAgICAgICAgICAgICAgICByaG8gPSAwLjI2MjcxNTYpCiMgc3BsaXQKaW52YXNpb24ubHMgPC0gc3BsaXQoaW52YXNpb25fZml0bmVzcy5kZjIsIHNlcShucm93KGludmFzaW9uX2ZpdG5lc3MuZGYyKSkpCgojIHJ1biBmdW5jdGlvbgptY2xhcHBseShpbnZhc2lvbi5scywgZ2V0X2ludmFzaW9uX2R5biwgbWMuY29yZXMgPSA0KQpgYGAKCgojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBpbXBvcnQgaW4gaW52YXNpb24gZHluYW1pY3MKaW52YXNpb25fZHluLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfaW52YXNpb25fZHluIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCmludmFzaW9uX2R5bi5scyA8LSBsYXBwbHkoaW52YXNpb25fZHluLmxzLCByZWFkX3BhcnF1ZXQpCgojIGZpbHRlciBhbmQgc28gb24KaW52YXNpb25fZHluLmxzMiA8LSBtY2xhcHBseShpbnZhc2lvbl9keW4ubHNbMTY3OjE3N10sIG1jLmNvcmVzID0gNCwgZnVuY3Rpb24oeCl7CiAgeDIgPC0geCAlPiUgCiAgICBmaWx0ZXIodmFyaWFibGUgPT0gIkkxIiB8IHZhcmlhYmxlID09ICJJZzEiIHwgdmFyaWFibGUgPT0gIkkyIiB8IHZhcmlhYmxlID09ICJJZzIiIHwgdmFyaWFibGUgPT0gIlIiKSAlPiUgCiAgICBtdXRhdGUoaWRfYWx0ID0gcGFzdGUobXV0X2lkLCByZXNfaWQpKSAlPiUgCiAgICBzZWxlY3QoaWRfYWx0LCB0aW1lLCB2YXJpYWJsZSwgdmFsdWUpICU+JSAKICAgIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUsIGlkX2NvbHMgPSBjKHRpbWUsIGlkX2FsdCkpICU+JQogIG11dGF0ZSh0b3RhbDEgPSBJMStJZzEsIHRvdGFsMiA9IEkyK0lnMikKICAKICB3cml0ZV9wYXJxdWV0KHgyLCBwYXN0ZTAoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2ludmFzaW9uLyIpLCB1bmlxdWUoeDIkaWRfYWx0KSwgIl9kYy5wYXJxdWV0IikpCn0pCgojIGZldGNoIGRhdGEKaW52YXNpb25fZHluLmxzMiA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfaW52YXNpb24iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKaW52YXNpb25fZHluLmxzMiA8LSBsYXBwbHkoaW52YXNpb25fZHluLmxzMiwgcmVhZF9wYXJxdWV0KQppbnZhc2lvbl9kYy5kZiA8LSBkby5jYWxsKHJiaW5kLCBpbnZhc2lvbl9keW4ubHMyKQppbnZhc2lvbl9kYy5kZiA8LSBpbnZhc2lvbl9kYy5kZiAlPiUgCiAgbXV0YXRlKG11dF9pZCA9IGdzdWIoIiAuKiIsICIiLCBpZF9hbHQpLAogICAgICAgICByZXNfaWQgPSBnc3ViKCIuKiAiLCAiIiwgaWRfYWx0KSkgJT4lIAogIGZpbHRlcihtdXRfaWQgIT0gcmVzX2lkKQojd3JpdGVfcGFycXVldChpbnZhc2lvbl9kYy5kZiwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2ludmFzaW9uX2RjLnBhcnF1ZXQiKSkKYGBgCgojIGZ1cnRoZXIgcHJvY2Vzc2luZwpgYGB7cn0KaW52YXNpb25fZGMuZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9pbnZhc2lvbl9kYy5wYXJxdWV0IikpCiMgZ2V0IHdpbm5lcnMgYW5kIGxvc2VycwppbnZhc2lvbl9maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfaW52YXNpb24uY3N2IikpCmludmFzaW9uX2RjLmRmMiA8LSBpbnZhc2lvbl9kYy5kZiAlPiUgCiAgbGVmdF9qb2luKGludmFzaW9uX2ZpdG5lc3MuZGYsIGJ5ID0gYygibXV0X2lkIiwgInJlc19pZCIpKSAlPiUgCiAgbXV0YXRlKAogIHRvdGFsX3dpbm5lciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3M+IDAgfiB0b3RhbDEsCiAgICBmaXRuZXNzPCAwIH4gdG90YWwyCiAgKSwKICB0b3RhbF9sb3NlciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3MgPiAwIH4gdG90YWwyLAogICAgZml0bmVzcyA8IDAgfiB0b3RhbDEKICApKSAlPiUgCiAgZmlsdGVyKGFicyhmaXRuZXNzKSA+IDAuNSkKYGBgCgojIHBsb3QKYGBge3J9CmludmFzaW9uX2RjLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IGludmFzaW9uX2RjLmRmMiwgYWVzKHg9IHRvdGFsX3dpbm5lciwgeSA9IFIsIGdyb3VwID0gaWRfYWx0LCBjb2xvciA9ICJXaW5uZXIiKSwgYWxwaGEgPSAwLjUsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGdlb21fcGF0aChkYXRhID0gaW52YXNpb25fZGMuZGYyLCBhZXMoeD0gdG90YWxfbG9zZXIsIHkgPSBSLCBncm91cCA9IGlkX2FsdCwgY29sb3IgPSAiTG9zZXIiKSwKICAgICAgICAgIGFscGhhID0gMC41LGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGxhYnMoY29sb3IgPSAiU3RhdHVzIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMiLCB5ID0gIlJCQyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIldpbm5lciIgPSAiIzQ1NzViNCIsIkxvc2VyIj0gIiNmYzhkNTkiKSkgICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSwgYWNjdXJhY3kgPSAwLjEpKSAlPiUgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCgojLS0tLS0tLS0tIHF1YW50aWZ5aW5nIGRpc2Vhc2UgY3VydmUgYXJlYSAtLS0tLS0tLS0tLS0jCiMgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGFyZWEgYmV0d2VlbiBzZXRzIG9mIHBvaW50cyAtPiBmcm9tIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzM2NzIyNjAvYXJlYS1jb3ZlcmVkLWJ5LWEtcG9pbnQtY2xvdWQtd2l0aC1yCmBgYHtyfQpsaWJyYXJ5KHNwbGFuY3MpCmNoYTwtZnVuY3Rpb24oZGYpewogIHggPC0gZGYkdG90YWwKICB5IDwtIGRmJFIKY2h1bGwoeCx5KS0+aQpyZXR1cm4oYXJlYXBsKGNiaW5kKHhbaV0seVtpXSkpKQp9CmBgYAoKIyBsb29wIHRvIGdldCBhcmVhOiBzaW5nbGUgaW5mZWN0aW9uCmBgYHtyfQojIHNwbGl0IGRmCnNpX2RjX2hpZ2gubHMgPC0gc3BsaXQoc2lfZGMuaGlnaCwgc2lfZGMuaGlnaCRlel9sYWJlbF9zaSkKc2lfZGNfcG9vci5scyA8LSBzcGxpdChzaV9kYy5wb29yLCBzaV9kYy5wb29yJGlkKQoKIyBnZXQgYXJlYQpzaV9kY19oaWdoLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoc2lfZGNfaGlnaC5scywgY2hhKSksIGlkX2FsdCA9IG5hbWVzKGxhcHBseShzaV9kY19oaWdoLmxzLCBjaGEpKSkKc2lfZGNfcG9vci5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KHNpX2RjX3Bvb3IubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoc2lfZGNfcG9vci5scywgY2hhKSkpCgoKIyBqb2luIHdpdGggZml0bmVzcwpzaV9maXRuZXNzLmRmIDwtIHNpX2ZpdG5lc3MuZGYgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCnNpX2RjX2hpZ2guYXJlYTIgPC0gc2lfZGNfaGlnaC5hcmVhICU+JSAKICBsZWZ0X2pvaW4oc2lfZml0bmVzcy5kZiwgYnkgPSBjKCJpZF9hbHQiID0gImV6X2xhYmVsX3NpIikpICU+JSAKICBzZWxlY3QodmFsdWUsIGFyZWEpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIlNpbmdsZSBpbmZlY3Rpb24iKQoKc2lfZGNfcG9vci5hcmVhMiA8LSBzaV9kY19wb29yLmFyZWEgJT4lIAogIGxlZnRfam9pbihzaV9maXRuZXNzLmRmLCBieSA9IGMoImlkX2FsdCIgPSAiaWQiKSkgJT4lIAogIHNlbGVjdCh2YWx1ZSwgYXJlYSkgJT4lIAogIG11dGF0ZShjb25kaXRpb24gPSAiU2luZ2xlIGluZmVjdGlvbiIpCmBgYAoKIyBjb2luZmVjdGlvbgpgYGB7cn0KIyBzcGxpdApjaV9kY19oaWdoLmxzIDwtIHNwbGl0KGNpX2RjLmhpZ2gyLCBjaV9kYy5oaWdoMiRlel9sYWJlbCkKY2lfZGNfcG9vci5scyA8LSBzcGxpdChjaV9kYy5wb29yLCBjaV9kYy5wb29yJGxhYmVsKQoKIyBydW4gZnVuY3Rpb24gdG8gZmluZCBhcmVhCmNpX2RjX2hpZ2guYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShjaV9kY19oaWdoLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KGNpX2RjX2hpZ2gubHMsIGNoYSkpLCB2YWx1ZSA9IHVuaXF1ZShjaV9kYy5oaWdoMiR2YWx1ZSkpCgpjaV9kY19wb29yLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoY2lfZGNfcG9vci5scywgY2hhKSksIGlkX2FsdCA9IG5hbWVzKGxhcHBseShjaV9kY19wb29yLmxzLCBjaGEpKSwgdmFsdWUgPSB1bmlxdWUoY2lfZGMucG9vciR2YWx1ZSkpCgojIGVkaXQgYW5kIGpvaW4KY2lfZGNfaGlnaC5hcmVhMiA8LSAgY2lfZGNfaGlnaC5hcmVhICU+JSAKICBzZWxlY3QoYXJlYSwgdmFsdWUpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIkNvLWluZmVjdGlvbiIpCgpjaV9kY19wb29yLmFyZWEyIDwtICBjaV9kY19wb29yLmFyZWEgJT4lIAogIHNlbGVjdChhcmVhLCB2YWx1ZSkgJT4lIAogIG11dGF0ZShjb25kaXRpb24gPSAiQ28taW5mZWN0aW9uIikKYGBgCgojIGR1YWwgY3VlCmBgYHtyfQojIHNwbGl0CmR1YWwuZGMgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjLnBhcnF1ZXQiKSkKZHVhbF9kYy5scyA8LSBzcGxpdChkdWFsLmRjLCBkdWFsLmRjJGxhYmVsX2FsdCkKCiMgZ2V0IGFyZWEKZHVhbF9kYy5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGR1YWxfZGMubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoZHVhbF9kYy5scywgY2hhKSkpCgojIGJpbmQgd2l0aCBmaXRuZXNzCmR1YWxfZml0bmVzcy5kZiA8LSBkdWFsX2ZpdG5lc3MuZGYgJT4lIG11dGF0ZShpZF9hbHQgPSBwYXN0ZShsYWJlbCwgIisiLCBsYWJlbF9iKSkKZHVhbF9kYy5hcmVhMiA8LSBkdWFsX2RjLmFyZWEgJT4lIAogIGxlZnRfam9pbihkdWFsX2ZpdG5lc3MuZGYsIGJ5ID0gImlkX2FsdCIpICU+JSAKICBzZWxlY3QoYXJlYSwgdmFsdWUpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIkR1YWwtY3VlIikgJT4lIAogIGZpbHRlcih2YWx1ZSA+IDIpCmR1YWxfZGMuYXJlYTIKYGBgCgojLS0tLS0tIGdldCBmaXR0ZWQgc2NhdHRlciBwbG90IGZvciBhbGwgc2luZ2xlIGluZmVjdGlvbiwgY28gaW5mZWN0aW9uLCBhbmQgZHVhbCBjdWUgLS0tLS0tLS0jCmBgYHtyfQojIHJiaW5kCnNpLmFyZWEgPC0gcmJpbmQoc2lfZGNfaGlnaC5hcmVhMiwgc2lfZGNfcG9vci5hcmVhMikKY2kuYXJlYSA8LSByYmluZChjaV9kY19oaWdoLmFyZWEyLCBjaV9kY19wb29yLmFyZWEyKQpkdWFsLmFyZWEgPC0gZHVhbF9kYy5hcmVhMgoKIyBwbG90CmxpYnJhcnkoImdncG1pc2MiKQoKc2lfYXJlYS5wbCA8LSBnZ3Bsb3QoZGF0YSA9IHNpLmFyZWEsIGFlcyh4ID0gYXJlYSwgeSA9IHZhbHVlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9wb2x5X2xpbmUoY29sb3IgPSAiYmxhY2siKSArCiAgc3RhdF9wb2x5X2VxKCkgKwogIGxhYnMoeCA9ICJBcmVhIiwgeSA9ICJGaXRuZXNzIiwgY29sb3IgPSAiU3RhdHVzIikgKwogIHRoZW1lX2J3KCkKCmNpX2FyZWEucGwgPC0gZ2dwbG90KGRhdGEgPSBjaS5hcmVhLCBhZXMoeCA9IGFyZWEsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfcG9seV9saW5lKGNvbG9yID0gImJsYWNrIikgKwogIHN0YXRfcG9seV9lcSgpICsKICBsYWJzKHggPSAiQXJlYSIsIHkgPSAiRml0bmVzcyIsIGNvbG9yID0gIlN0YXR1cyIpICsKICB0aGVtZV9idygpCgpkdWFsX2FyZWEucGwgPC0gZ2dwbG90KGRhdGEgPSBkdWFsLmFyZWEsIGFlcyh4ID0gYXJlYSwgeSA9IHZhbHVlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9wb2x5X2xpbmUoY29sb3I9ICJibGFjayIpICsKICBzdGF0X3BvbHlfZXEoKSArCiAgbGFicyh4ID0gIkFyZWEiLCB5ID0gIkZpdG5lc3MiLCBjb2xvciA9ICJTdGF0dXMiKSArCiAgdGhlbWVfYncoKQpgYGAKCgojLS0tLS0tLSBwbG90IHRvZ2V0aGVyIHdpdGggZGlzZWFzZSBjdXJ2ZSAtLS0tLS0tLSMKYGBge3J9CiMgc2luZ2xlIGluZmVjdGlvbgpzaV92aXIucGwgPC0gZ2dhcnJhbmdlKHNpX2RjLnBsLCBzaV9hcmVhLnBsLCBhbGlnbiA9ICJ2Iiwgd2lkdGhzID0gYygxLCAwLjQ1KSkKCiMgY28taW5mZWN0aW9uCmNpX3Zpci5wbCA8LSBnZ2FycmFuZ2UoY2lfZGMucGwsIGNpX2FyZWEucGwsIGFsaWduID0gInYiLCB3aWR0aHMgPSBjKDEsIDAuNDUpKQoKIyBkdWFsLWN1ZQpkdWFsX3Zpci5wbCA8LSBnZ2FycmFuZ2UoZHVhbF9kYy5wbCwgZHVhbF9hcmVhLnBsLCBhbGlnbiA9ICJ2Iiwgd2lkdGhzID0gYygxLCAwLjQ1KSkKYGBgCgoKIy0tLS0tLS0tLSBzdGF0aWMgYXJlYSBjb21wYXJpc29uIC0tLS0tLS0tLS0tLS0jCiMgY29tcHV0ZSBhcmVhCmBgYHtyfQojIGltcG9ydCBpbiBkYyBkeW5hbWljIGFuZCBmaXRuZXNzCnN0YXRpY19kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCnN0YXRpY19maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQoKIyBnZXQgd2lubmVyIGFuZCBsb3NlcgpzdGF0aWNfZGMuZGY0IDwtIHN0YXRpY19kYy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzdGF0aWNfZml0bmVzcy5kZiwgaWRfMSwgaWRfMiwgZml0bmVzc19kaWZmZXJlbmNlKSwgYnkgPSBjKCJpZF8xIiwgImlkXzIiKSkgJT4lCiAgZmlsdGVyKGlkXzEgIT0gaWRfMikgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwxLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwyCiAgKSwKICB0b3RhbF9sb3NlciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDEKICApKSU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3NfZGlmZmVyZW5jZSkgPiAwLjUpCgojIHNwbGl0IGJ5IHdpbm5lciBhbmQgbG9zZXIKc3RhdGljX2RjLmxzMSA8LSBzcGxpdChzZWxlY3Qoc3RhdGljX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF93aW5uZXIpLCBzdGF0aWNfZGMuZGY0JGlkX2FsdCkKc3RhdGljX2RjLmxzMiA8LSBzcGxpdChzZWxlY3Qoc3RhdGljX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF9sb3NlciksIHN0YXRpY19kYy5kZjQkaWRfYWx0KQoKIyBnZXQgYXJlYQpzdGF0aWNfd2luLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoc3RhdGljX2RjLmxzMSwgY2hhKSksIHN0YXR1cyA9ICJXaW5uZXIiKQpzdGF0aWNfbG9zZXIuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzdGF0aWNfZGMubHMyLCBjaGEpKSwgc3RhdHVzID0gIkxvc2VyIikKCiMgcGFpcgpzdGF0aWMuYXJlYSA8LSBjYmluZChzZWxlY3Qoc3RhdGljX3dpbi5hcmVhLCBXaW5uZXIgPSBhcmVhKSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHN0YXRpY19sb3Nlci5hcmVhLCBMb3NlciA9IGFyZWEpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFdpbm5lcj5Mb3NlciwgIldpbm5lciBsYXJnZXIgYXJlYSIsICJMb3NlciBsYXJnZXIgYXJlYSIpKQpgYGAKCiMgcGxvdCBzdGF0aWMKYGBge3J9CnN0YXRpY19hcmVhLnBsIDwtIGdncGFpcmVkKHN0YXRpYy5hcmVhLCBjb25kMSA9ICJXaW5uZXIiLCBjb25kMiA9ICJMb3NlciIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuMikgKwogIGxhYnMoeCA9ICJTdGF0dXMiLCB5ID0gIkFyZWEiLCBjb2xvciA9ICJDb21wYXJpc29uXG4oU3RhdGljKSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTG9zZXIgbGFyZ2VyIGFyZWEiID0gIiNmYzhkNTkiLCAiV2lubmVyIGxhcmdlciBhcmVhIiA9ICIjNDU3NWI0IikpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAwKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChucm93PTIsYnlyb3c9VFJVRSkpCmBgYAoKCiMtLS0tLS0tLS0gaW52YXNpb24gYXJlYSBjb21wYXJpc29uIC0tLS0tLS0tLS0tLS0tLS0tIwojIGdldCBhcmVhCmBgYHtyfQojIGltcG9ydCBpbiBkYyBkeW5hbWljIGFuZCBmaXRuZXNzCmludmFzaW9uX2RjLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvaW52YXNpb25fZGMucGFycXVldCIpKQppbnZhc2lvbl9maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfaW52YXNpb24uY3N2IikpCgppbnZhc2lvbl9kYy5kZjQgPC0gaW52YXNpb25fZGMuZGYgJT4lIAogIGxlZnRfam9pbihpbnZhc2lvbl9maXRuZXNzLmRmLCBieSA9IGMoIm11dF9pZCIsICJyZXNfaWQiKSkgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzPiAwIH4gdG90YWwxLAogICAgZml0bmVzczwgMCB+IHRvdGFsMgogICksCiAgdG90YWxfbG9zZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3MgPCAwIH4gdG90YWwxCiAgKSkgJT4lIAogIGZpbHRlcihhYnMoZml0bmVzcykgPiAwLjUpCgojIHNwbGl0IGJ5IHdpbm5lciBhbmQgbG9zZXIKaW52YXNpb25fZGMubHMxIDwtIHNwbGl0KHNlbGVjdChpbnZhc2lvbl9kYy5kZjQsIFIsIHRvdGFsID0gdG90YWxfd2lubmVyKSwgaW52YXNpb25fZGMuZGY0JGlkX2FsdCkKaW52YXNpb25fZGMubHMyIDwtIHNwbGl0KHNlbGVjdChpbnZhc2lvbl9kYy5kZjQsIFIsIHRvdGFsID0gdG90YWxfbG9zZXIpLCBpbnZhc2lvbl9kYy5kZjQkaWRfYWx0KQoKIyBnZXQgYXJlYQppbnZhc2lvbl93aW4uYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShpbnZhc2lvbl9kYy5sczEsIGNoYSkpLCBzdGF0dXMgPSAiV2lubmVyIikKaW52YXNpb25fbG9zZXIuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShpbnZhc2lvbl9kYy5sczIsIGNoYSkpLCBzdGF0dXMgPSAiTG9zZXIiKQoKIyBwYWlyCmludmFzaW9uLmFyZWEgPC0gY2JpbmQoc2VsZWN0KGludmFzaW9uX3dpbi5hcmVhLCBXaW5uZXIgPSBhcmVhKSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGludmFzaW9uX2xvc2VyLmFyZWEsIExvc2VyID0gYXJlYSkpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoV2lubmVyPkxvc2VyLCAiV2lubmVyIGxhcmdlciBhcmVhIiwgIkxvc2VyIGxhcmdlciBhcmVhIikpCmBgYAoKIyBwbG90CmBgYHtyfQppbnZhc2lvbl9hcmVhLnBsIDwtZ2dwYWlyZWQoaW52YXNpb24uYXJlYSwgY29uZDEgPSAiV2lubmVyIiwgY29uZDIgPSAiTG9zZXIiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiU3RhdHVzIiwgeSA9ICJBcmVhIiwgY29sb3IgPSAiQ29tcGFyaXNvblxuKEludmFzaXZlKSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTG9zZXIgbGFyZ2VyIGFyZWEiID0gIiNmYzhkNTkiLCAiV2lubmVyIGxhcmdlciBhcmVhIiA9ICIjNDU3NWI0IikpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAwKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChucm93PTIsYnlyb3c9VFJVRSkpCiAgCmBgYAoKIy0tLS0tLSBwbG90IHRvZ2V0aGVyIC0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIHBhaXJ3aXNlIGNvbXBhcmlzb24gZm9yIHN0YXRpYyBhbmQgaW52YXNpdmUgY29tZXB0aXRpb24KaGV0ZXJvY3VlX2NvbXAucGwgPC0gZ2dhcnJhbmdlKHN0YXRpY19hcmVhLnBsLCBpbnZhc2lvbl9hcmVhLnBsLCBuY29sID0gMiwgbnJvdyA9IDEsIGFsaWduID0gInYiKQoKIyBqb2luIGludGhlIG90aGVyIGRpc2Vhc2UgY3VydmVzCmdnYXJyYW5nZShzaV92aXIucGwsIGNpX3Zpci5wbCwgZHVhbF92aXIucGwsIGhldGVyb2N1ZV9jb21wLnBsLCBuY29sID0gMiwgbnJvdyA9IDIsIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIiwgIkQiKSwgaGVpZ2h0cyA9IGMoMSwgMC44KSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3ZpcnVsZW5jZS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNjAwLCBzY2FsZSA9IDIsIGRwaT0zMDAsIGJnID0gIndoaXRlIikKYGBgCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBkdWFsIGN1ZSBkeW5hbWljcyBmaWd1cmUKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwoKIyBnZXQgZHVhbCBkeW5hbWljcwpgYGB7cn0KZHVhbC5keW4gPC0gY2hhYmF1ZGlfc2lfY2xlYW4oCiAgcGFyYW1ldGVyc19jciA9IGMoNC40NDYxOTIwMzMsCTEwLjk3NTE4Mjc1LAkxLjM4NzYyODE3LAkyMy4zMDU5MjU0LAktMy40NTIwNTIzNzEsCS0xOC4wMDcwNjkyLAkzOS42NjYxNDIyNiwJLTMuNTQ1MTkzMTQxLAkxOC43ODM1MDc5OSksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMzAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSg2LCA3LCBieSA9IDEvNTAwKSwKICBjdWVfcmFuZ2VfYiA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwKSwKICBjdWUgPSAiUiIsCiAgY3VlX2IgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgbG9nX2N1ZV9iID0gImxvZzEwIiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVAopCgojIGZpbHRlciBvdXQgcmVsZXZlbnQgZGF0YWZyYW1lcwpkdWFsLmR5bl9mIDwtIGR1YWwuZHluICU+JSAKICBmaWx0ZXIodmFyaWFibGUgJWluJSBjKCJJIiwgIklnIiwgIkciLCAiUiIsICJOIiwgIlciKSkKCiMgY3Igb25seQpkdWFsLmR5bl9jciA8LSBkdWFsLmR5biAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX0kucGx0IDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNSkpLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNSkpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjEwXjUsIG5hbWU9IkFzZXh1YWwgaVJCQyBwZXIgwrVMIikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmR1YWxfSWcucGx0IDwtZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJZyIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNSkpLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSWciICYgcm93X251bWJlcigpICUlIDEwMDAgPT0gMCksIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjUpKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LioxMF41LCBuYW1lPSJTZXh1YWwgaVJCQyBwZXIgwrVMIikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmR1YWxfRy5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIkciKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjQpKSwKICAgICAgICAgICAgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIkciICYgcm93X251bWJlcigpICUlIDEwMDAgPT0gMCksIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjQpKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LioxMF40LCBuYW1lPSJHYW1ldG9jeXRlIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9SLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiUiIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNykpLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiUiIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNykpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjEwXjcsIG5hbWU9IlJCQyBwZXIgwrVMIikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmR1YWxfTi5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIk4iKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUqMTApLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiTiIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSoxMCksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMC4xLCBuYW1lPSJJbmRpc2NyaW1pbmF0ZSBpbW11bml0eSIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpkdWFsX1cucGx0IDwtZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJXIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKjIpLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiVyIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSoyKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LiowLjUsIG5hbWU9IlRhcmdldGVkIGltbXVuaXR5IikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIHBsb3QgdG9nZXRoZXIKYGBge3J9CmdnYXJyYW5nZShkdWFsX0kucGx0LCBkdWFsX0lnLnBsdCwgZHVhbF9HLnBsdCwgZHVhbF9SLnBsdCwgZHVhbF9OLnBsdCwgZHVhbF9XLnBsdCwgbnJvdyA9IDMsIG5jb2wgPSAyLCBhbGlnbiA9ICJodiIsIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIsICJGIikpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2R1YWxfZHluLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDIwMDAsIHNjYWxlID0gMSwgZHBpPTMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBTaW5nbGUgYW5kIGNvLWluZmVjdGlvbiB2ZXJpZmljYXRpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIHNpbmdsZSBpbmZlY3Rpb24KYGBge3J9CiMgaW1wb3J0IGluIGFsbCBzaW5nbGUgaW5mZWN0aW9uIGRhdGEKc2lfdmFsLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvc2lfdmFsaWRhdGlvbiIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCgpzaV92YWwuZGYgPC0gbGFwcGx5KHNpX3ZhbC5scywgcmVhZC5jc3YpCnNpX3ZhbC5kZiA8LSBkby5jYWxsKHJiaW5kLCBzaV92YWwuZGYpCgojIGdldCBtYXggZml0bmVzcyBmcm9tIHNpbXVsYXRpb24uIGxlZnQgam9pbiB3aXRoIHNpX29wdApzaV9vcHQuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9zaV9vcHQuY3N2IikpCgojIHdlIGNhbiBzZWUgdGhhdCBhbGwgb2YgdGhlIHJhbmRvbWx5IHNpbXVsYXRlZCBtb2RlbHMgaGF2ZSBhIGZpdG5lc3MgdmFsdWUgdGhhdCBpcyBsZXNzIHRoYW4gdGhlIG9wdGltaXplZCBtb2RlbApzaV92YWwuZGYyIDwtIHNlbGVjdChzaV92YWwuZGYsIFYxLCBpZCkgJT4lCiAgbGVmdF9qb2luKHNpX29wdC5kZiwgYnkgPWMoImlkIiA9ICJpZCIpKSAlPiUgCiAgbXV0YXRlKGZpdG5lc3NfZGlmZmVyZW5jZSA9IGZpdG5lc3NfMjAgLSBWMSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX3NpLCBlel9sYWJlbF9zaSksIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCmBgYAoKIyMjIE1vZGVsIHZhbGlkYXRpb24KYGBge3J9CiMgcmVhZCBpbiB0aGUgcmVzdWx0cyBmaWxlCmNpX3ZhbC5scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL2NpX3ZhbGlkYXRpb24iKSwgcGF0dGVybiA9ICIqLmNzdiIsIGZ1bGwubmFtZXMgPSBUKQpjaV92YWwubHMyIDwtIGxhcHBseShjaV92YWwubHMsIHJlYWQuY3N2KQpjaV92YWwuZGYgPC0gZG8uY2FsbChyYmluZCwgY2lfdmFsLmxzMikKCmNpX3ZhbC5kZjIKY2lfdmFsLmRmMiA8LSBjaV92YWwuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGxhYmVsX2NpLCBlel9sYWJlbCksIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCmBgYAoKIyBwbG90CmBgYHtyfQpzaV92YWwucGx0IDwtIGdncGxvdChkYXRhID0gc2lfdmFsLmRmMiwgYWVzKHggPSBmaXRuZXNzX2RpZmZlcmVuY2UpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiI2ZjOGQ1OSIpICsKICBmYWNldF93cmFwKH5lel9sYWJlbF9zaSwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gMykgKwogIGxhYnMoeCA9ICJPcHRpbWl6ZWQgZml0bmVzcyAtIHJhbmRvbSBmaXRuZXNzIiwgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfYncoKQoKY2lfdmFsLnBsdCA8LSBnZ3Bsb3QoZGF0YSA9IGNpX3ZhbC5kZjIsIGFlcyh4ID0gVjEpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiI2ZjOGQ1OSIpICsKICBmYWNldF93cmFwKH5lel9sYWJlbCwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gNCkgKwogIGxhYnMoeCA9ICJGaXRuZXNzIGRpZmZlcmVuY2UgYmV0d2Vlblxub3B0aW1pemVkIGFuZCByYW5kb20gc3RyYWluIiwgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfYncoKQoKZ2dhcnJhbmdlKHNpX3ZhbC5wbHQsIGNpX3ZhbC5wbHQsIGFsaWduID0gImh2IiwgbGFiZWxzID0gYygiQSIsICJCIiksIHdpZHRocyA9IGMoMyw0KSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vdmFsaWRhdGlvbi50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxMzAwLCBzY2FsZSA9IDEuNiwgZHBpPTMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09IwojIE1vbnRlIGNhcmxvIGR5bmFtaWNzIHN1cHBsZW1lbnRhcnkKIz09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgcnVuIGNvZGUgaW4gcmVwb3J0IDE2CmBgYHtyfQptY19keW5fYSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSByZWZlcmVuY2UuZGYsIGFlcyh4ID0gdGltZSwgeSA9IGNyKSkgKwogIGdlb21fcmliYm9uKGRhdGEgPSBkaWZmLmRmLCBhZXMoeCA9IHRpbWUsIHltaW4gPSBjcl9ib3QsIHltYXggPSBjcl90b3ApLCBhbHBoYSA9IDAuNSwgZmlsbCA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmN1ZSwgbmNvbCA9IDIpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9idygpCiAgCiMgcGxvdCBmaXRuZXNzIHRpbWVzZXJpZXMuIFdoZW4gaWYgdGluZXNzIGxvc3Q/IEF0IHRoZSBsYXR0ZXIgcGFydAptY19keW5fYiAgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gcmVmZXJlbmNlLmRmLCBhZXMoeCA9IHRpbWUsIHkgPSB0YXUpKSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGRpZmYuZGYsIGFlcyh4ID0gdGltZSwgeW1pbiA9IHRhdV9ib3QsIHltYXggPSB0YXVfdG9wKSwgYWxwaGEgPSAwLjUsIGZpbGwgPSAiI2ZjOGQ1OSIpICsKICBmYWNldF93cmFwKH5jdWUsIG5jb2wgPSAyKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJUcmFuc21pc3Npb24gcG90ZW50aWFsIikgKwogIHRoZW1lX2J3KCkKCmdnYXJyYW5nZShtY19keW5fYSwgbWNfZHluX2IsIG5jb2wgPSAxLCBhbGlnbiA9ICJ2IiwgbGFiZWxzID0gYygiQSIsICJCIikpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL01DX2R5bi50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAyNjAwLCBzY2FsZSA9IDEsIGRwaT0zMDAsIGJnID0gIndoaXRlIikKYGBgCgoKCg==